¿Por qué puedo cambiar el valor de una constante en JavaScript?

101

Sé que ES6 aún no está estandarizado, pero muchos navegadores actualmente admiten const palabras clave en JS.

En las especificaciones, está escrito que:

El valor de una constante no puede cambiar mediante la reasignación y una constante no se puede volver a declarar. Por ello, aunque es posible declarar una constante sin inicializarla, sería inútil hacerlo.

y cuando hago algo como esto:

const xxx = 6;
xxx = 999;
xxx++;
const yyy = [];
yyy = 'string';
yyy = [15, 'a'];

Veo que todo está bien, xxxestá quieto 6y yyyestá [].

Pero si lo hago yyy.push(6); yyy.push(1);, mi matriz constante se ha cambiado. Ahora mismo lo es [6, 1]y por cierto todavía no puedo cambiarlo yyy = 1;.

¿Es un error o me falta algo? Lo probé en el último Chrome y FF29.

Salvador Dalí
fuente
1
¿Puedes simplemente crear una clase, declarar la variable y asignar su valor dentro de la clase? Luego, cree un GETTER para esa variable; y no implemente un setter. Debería implementar una constante ...
Andrew
8
@Andrew gracias, pero no pregunto cómo puedo hacer esto. Tengo curiosidad por saber por qué la palabra clave const se comporta de esta manera.
Salvador Dali

Respuestas:

172

La documentación dice:

... la constante no puede cambiar mediante la reasignación
... la constante no se puede volver a declarar

Cuando está agregando a una matriz u objeto, no está reasignando ni volviendo a declarar la constante, ya está declarada y asignada, solo está agregando a la "lista" a la que apunta la constante.

Entonces esto funciona bien:

const x = {};

x.foo = 'bar';

console.log(x); // {foo : 'bar'}

x.foo = 'bar2';

console.log(x); // {foo : 'bar2'}  

y esto:

const y = [];

y.push('foo');

console.log(y); // ['foo']

y.unshift("foo2");

console.log(y); // ['foo2', 'foo']

y.pop();

console.log(y); // ['foo2']

pero ninguno de estos:

const x = {};
x = {foo: 'bar'}; // error - re-assigning

const y = ['foo'];
const y = ['bar']; // error - re-declaring

const foo = 'bar'; 
foo = 'bar2';       // error - can not re-assign
var foo = 'bar3';   // error - already declared
function foo() {};  // error - already declared
adeneo
fuente
4
¿Quiere decir que esto no es un error, pero debería funcionar de esta manera? Porque pensé que la idea de la constante es que no se puede cambiar. Básicamente, un programador confía en que no importa lo que suceda, nada puede cambiar el valor dentro de mi constante.
Salvador Dali
2
Creo que no es tan fácil, en este caso el valor de la constante es una matriz de elementos específicos. Cambiar cualquier cosa significa que cambia el valor .
veritas
6
Sí, se supone que funciona de esta manera, no está reasignando la constante, sigue siendo la misma referencia, solo está agregando a la matriz las referencias constantes, y las matrices y los objetos son como "listas", modificarlos sí no cambiar la referencia ni volver a declarar la constante.
adeneo
26
@SalvadorDali: constante y de solo lectura son dos cosas diferentes. Su variable es constante , pero la matriz a la que apunta no es de solo lectura
Matt Burland
43

Esto sucede porque su constante está almacenando una referencia a la matriz. Cuando une algo en su matriz, no está modificando su valor constante, sino la matriz a la que apunta. Lo mismo sucedería si asignara un objeto a una constante e intentara modificar alguna propiedad de la misma.

Si desea congelar una matriz u objeto para que no se pueda modificar, puede usar el Object.freezemétodo, que ya es parte de ECMAScript 5.

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]
Guilherme Sehn
fuente
1
Por esa misma lógica, una constante fiveestablecida en 5 en realidad no tiene un valor de 5, es solo una referencia al número 5. Entonces, si lo hago, five++no estoy cambiando la constante, solo el número al que apunta.
Anthony
3
@Anthony, la referencia solo funciona para matrices y objetos, no valores primitivos
Guilherme Sehn
1
@Anthony En tu ejemplo, estás cambiando el número al que fiveapunta la variable (la variable fivesolía ser una etiqueta para el número 5, ahora apunta a un número diferente: 6). En el ejemplo de la pregunta (y esta respuesta), xsiempre apunta a la misma lista; si xes constante, no puede hacer que apunte a una lista diferente. La única diferencia es que la misma lista puede crecer o reducirse; esto es algo solo posible para matrices y objetos y no para primitivas.
ShreevatsaR
9

Este es un comportamiento consistente con todos los lenguajes de programación que se me ocurren.

Considere C: las matrices son solo punteros glorificados. Una matriz constante solo significa que el valor del puntero no cambiará, pero de hecho los datos contenidos en esa dirección son gratuitos.

En javascript, se le permite llamar a métodos de objetos constantes (por supuesto, ¡de lo contrario los objetos constantes no servirían de mucho!). Estos métodos pueden tener el efecto secundario de modificar el objeto. Dado que las matrices en javascript son objetos, este comportamiento también se aplica a ellas.

Todo lo que está seguro es que la constante siempre apuntará al mismo objeto. Las propiedades del objeto en sí pueden cambiar libremente.

jueves
fuente
4

La declaración const crea una referencia de solo lectura a un valor. No significa que el valor que tiene sea inmutable, solo que el identificador de variable no se puede reasignar. Por ejemplo, en el caso de que el contenido sea un objeto, esto significa que el contenido del objeto (por ejemplo, sus parámetros) se puede modificar.

Además, una nota también importante:

Las constantes globales no se convierten en propiedades del objeto de ventana ...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

Benjamin West
fuente
3

Creo que esto le dará más claridad sobre el tema: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 .

Básicamente, se reduce a que constsiempre apunta a la misma dirección en la memoria. Puede cambiar el valor almacenado en esa dirección pero no puede cambiar la direcciónconst que apunta también.

La definición de lo constque mencionó será cierta cuando constapunte a una dirección que tenga un valor primitivo. Esto se debe a que no puede asignar un valor a esto constsin cambiar su dirección (porque así es como funciona la asignación de valores primitivos) y constno se permite cambiar la dirección de a .

Donde, como si constapuntara a un valor no primitivo, es posible editar el valor de la dirección.

Zyxmn
fuente
1

Encontré este artículo mientras buscaba por qué pude actualizar un Objeto incluso después de definirlo como const. Entonces, el punto aquí es que no es el Objeto directamente sino los atributos que contiene los que pueden actualizarse.

Por ejemplo, mi Objeto se ve así:

const number = {
    id:5,
    name:'Bob'
};

Las respuestas anteriores señalaron correctamente que es el Objeto el que es constante y no su atributo. Por lo tanto, podré actualizar la identificación o el nombre haciendo:

number.name = 'John';

Pero, no podré actualizar el Objeto en sí como:

number = {
    id:5,
    name:'John'
  };

TypeError: Assignment to constant variable.
Atul O Holic
fuente
1
su ejemplo es práctico y descripciones correctas
Ebrahim
0

Porque en const puedes cambiar los valores de un objeto, por lo que el objeto no almacena los datos de la asignación, sino que los apunta. por lo que hay una diferencia entre primitivas y objetos en Javascript.


fuente