Primitivo

En JavaScript, un primitive (valor primitivo, tipo de dato primitivo) son datos que no son un objeto y no tienen métodos. Hay 6 tipos de datos primitivos: string, number, bigint, boolean, undefined y symbol. También hay null, que aparentemente es primitivo, pero de hecho es un caso especial para cada Object: y cualquier tipo estructurado se deriva de null por la Cadena de prototipos.

La mayoría de las veces, un valor primitivo se representa directamente en el nivel más bajo de la implementación del lenguaje.

Todos los primitivos son inmutables, es decir, no se pueden modificar. Es importante no confundir un primitivo en sí mismo con un valor primitivo asignado a una variable. Se puede reasignar un nuevo valor a la variable, pero el valor existente no se puede cambiar de la misma forma en que se pueden modificar los objetos, los arreglos y las funciones.

Ejemplo

Este ejemplo te ayudará a comprender que los valores primitivos son inmutables.

JavaScript

js
// El uso de un método de cadena no modifica la cadena
var bar = "baz";
console.log(bar); // baz
bar.toUpperCase();
console.log(bar); // baz

// El uso de un método de arreglo muta el arreglo
var foo = [];
console.log(foo); // []
foo.push("plugh");
console.log(foo); // ["plugh"]

// La asignación le da al primitivo un nuevo valor (no lo muta)
bar = bar.toUpperCase(); // BAZ

Un primitivo se puede reemplazar, pero no se puede modificar directamente.

Otro ejemplo [paso a paso]

El siguiente ejemplo te ayudará a analizar cómo se ocupa JavaScript de los primitivos.

JavaScript

js
// El primitivo
let foo = 5;

// Define una función que debería cambiar el valor primitivo
function addTwo(num) {
  num += 2;
}
// Otra función que intenta hacer lo mismo
function addTwo_v2(foo) {
  foo += 2;
}

// Llama a tu primera función mientras pasas el primitivo como argumento
addTwo(foo);
// Obtiene el valor primitivo actual
console.log(foo); // 5

// Intenta de nuevo con tu segunda función...
addTwo_v2(foo);
console.log(foo); // 5

¿Esperaba que fuera 7 en lugar de 5?, si es así, lee cómo se ejecuta este código:

  • Para las llamadas a las funciones addTwo y addTwo_v2, JavaScript busca el valor del identificador foo. Encuentra correctamente tu variable instanciada con la primera declaración
  • Después de encontrarla, evalúa la expresión, foo se reemplaza por 5 y el motor de JavaScript pasa ese valor a las funciones como argumento
  • Antes de ejecutar las declaraciones dentro del cuerpo de las funciones, JavaScript toma una copia del argumento originalmente pasado (que es un primitivo) y crea una copia local. Estas copias, que existen solo dentro del ámbito de las funciones, son accesibles a través de los identificadores que especificaste en las definiciones de las funciones (num para addTwo, foo para addTwo_v2)
  • Luego, se ejecutan las instrucciones de las funciones:
    • En la primera función, se creó una variable num local. ¡Estas aumentando su valor en 2, no el valor original de foo!
    • En la segunda función, se creó una variable foo local. ¡Esto incrementa su valor en 2, no el valor original (externo) de foo!, además, en esta situación, no se puede acceder directamente a la variable foo externa. Esto se debe al alcance léxico de JavaScript y al ensombrecimiento de variables resultante. El foo local oculta al foo externo. Para obtener más información, consulta Cierres. (Ten en cuenta que window.foo aún se podría usar para acceder a la variable foo externa).
  • En conclusión, cualquier cambio dentro de tus funciones no afectará a la foo original en absoluto, ya que estas modificando copias de la misma.

Es por eso que los primitivos son inmutables: en lugar de cambiarlos directamente, modificas una copia, sin afectar el original.

Envolturas de objetos primitivos en JavaScript

A excepción de null y undefined, todos los valores primitivos tienen objetos equivalentes que envuelven los valores primitivos:

  • String para el string primitivo.
  • Number para el number primitivo.
  • BigInt para el bigint primitivo.
  • Boolean para el boolean primitivo.
  • Symbol para el symbol primitivo.

El método valueOf() del contenedor devuelve el valor primitivo.

Véase también