Pourquoi puis-je changer la valeur d'une constante en javascript

101

Je sais que ES6 n'est pas encore standardisé, mais un nombreux navigateurs prennent actuellement en charge les const mots-clés dans JS.

Dans la spécification, il est écrit que:

La valeur d'une constante ne peut pas changer par une réaffectation et une constante ne peut pas être déclarée à nouveau. Pour cette raison, bien qu'il soit possible de déclarer une constante sans l'initialiser, il serait inutile de le faire.

et quand je fais quelque chose comme ça:

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

Je vois que tout va bien xxxest toujours 6etyyy est[] .

Mais si je le fais yyy.push(6); yyy.push(1);, mon tableau constant a été changé. En ce moment, c'est [6, 1]et d'ailleurs je ne peux toujours pas le changer avec yyy = 1;.

Est-ce un bug ou est-ce que je manque quelque chose? Je l'ai essayé dans le dernier chrome et FF29

Salvador Dali
la source
1
Pouvez-vous simplement créer une classe, déclarer la variable et affecter sa valeur à l'intérieur de la classe. Ensuite, créez un GETTER pour cette variable; et n'implémentez pas de setter. Il devrait implémenter une constante ...
Andrew
8
@Andrew merci, mais je ne demande pas comment puis-je faire ça. Je suis curieux de savoir pourquoi le mot-clé const se comporte de cette façon.
Salvador Dali

Réponses:

172

La documentation déclare:

... la constante ne peut pas changer par réassignation
... la constante ne peut pas être déclarée à nouveau

Lorsque vous ajoutez à un tableau ou à un objet que vous ne réassignez pas ou ne re-déclarez pas la constante, elle est déjà déclarée et affectée, vous ajoutez simplement à la "liste" vers laquelle pointe la constante.

Donc, cela fonctionne bien:

const x = {};

x.foo = 'bar';

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

x.foo = 'bar2';

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

et ça:

const y = [];

y.push('foo');

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

y.unshift("foo2");

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

y.pop();

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

mais ni l'un ni l'autre:

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
la source
4
donc vous voulez dire que ce n'est pas un bug, mais cela devrait fonctionner de cette façon? Parce que je pensais que l'idée de la constante est qu'elle ne peut pas être modifiée. Fondamentalement, un programmeur a confiance que quoi qu'il arrive, rien ne peut changer la valeur à l'intérieur de ma constante.
Salvador Dali
2
Je pense que ce n'est pas si facile, dans ce cas, la valeur de la constante est un tableau d'éléments spécifiques. Changer quoi que ce soit signifie que vous modifiez la valeur .
veritas
6
Oui, c'est censé fonctionner de cette façon, vous ne réassignez pas la constante, c'est toujours la même référence, vous ajoutez simplement au tableau les références de constante, et les tableaux et les objets sont comme des "listes", les modifier le fait ne changez pas la référence ou ne déclarez pas à nouveau la constante.
adeneo
26
@SalvadorDali: constante et lecture seule sont deux choses différentes. Votre variable est constante , mais le tableau vers lequel elle pointe n'est pas en lecture seule
Matt Burland
43

Cela se produit parce que votre constante stocke en fait une référence au tableau. Lorsque vous joignez quelque chose dans votre tableau, vous ne modifiez pas votre valeur constante, mais le tableau vers lequel elle pointe. La même chose se produirait si vous affectiez un objet à une constante et tentiez de modifier l'une de ses propriétés.

Si vous souhaitez figer un tableau ou un objet afin qu'il ne puisse pas être modifié, vous pouvez utiliser la Object.freezeméthode, qui fait déjà partie d'ECMAScript 5.

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]
Guilherme Sehn
la source
1
Par cette même logique, une constante fivefixée à 5 n'a pas réellement une valeur de 5, c'est juste une référence au nombre 5. Donc si je le fais, five++je ne change pas la constante, juste le nombre vers lequel elle pointe.
Anthony
3
@Anthony la chose de référence ne fonctionne que pour les tableaux et les objets, pas les valeurs primitives
Guilherme Sehn
1
@Anthony Dans votre exemple, vous changez le nombre vers lequel fivepointe la variable (la variable fiveétait autrefois une étiquette pour le nombre 5, maintenant elle pointe vers un nombre différent: 6). Dans l'exemple de la question (et de cette réponse), xpointe toujours vers la même liste; si xest const, vous ne pouvez pas le faire pointer vers une liste différente. La seule différence est que la même liste peut augmenter ou diminuer; c'est quelque chose de possible uniquement pour les tableaux et les objets et non pour les primitifs.
ShreevatsaR
9

C'est un comportement cohérent avec tous les langages de programmation auxquels je peux penser.

Considérez que les tableaux C ne sont que des pointeurs glorifiés. Un tableau constant signifie seulement que la valeur du pointeur ne changera pas - mais en fait, les données contenues à cette adresse sont libres de le faire.

En javascript, vous êtes autorisé à appeler des méthodes d'objets constants (bien sûr - sinon les objets constants ne serviraient pas à grand-chose!) Ces méthodes pourraient avoir pour effet secondaire de modifier l'objet. Puisque les tableaux en javascript sont des objets, ce comportement s'applique également à eux.

Tout ce dont vous êtes assuré, c'est que la constante pointera toujours vers le même objet. Les propriétés de l'objet lui-même sont libres de changer.

jeudi
la source
4

La déclaration const crée une référence en lecture seule à une valeur. Cela ne signifie pas que la valeur qu'il contient est immuable, mais simplement que l'identificateur de variable ne peut pas être réaffecté. Par exemple, dans le cas où le contenu est un objet, cela signifie que le contenu de l'objet (par exemple, ses paramètres) peut être modifié.

En outre, une note également importante:

Les constantes globales ne deviennent pas des propriétés de l'objet window ...

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

Benjamin West
la source
3

Je pense que cela vous donnerait plus de clarté sur la question: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 .

En gros, cela revient à constpointer toujours vers la même adresse en mémoire. Vous pouvez modifier la valeur stockée dans cette adresse, mais vous ne pouvez pas non plus modifier l'adresse constpointée.

La définition de constvous mentionnée sera vraie lorsque le constpointe vers une adresse contenant une valeur primitive. En effet, vous ne pouvez pas attribuer une valeur à cela constsans changer son adresse (car c'est ainsi que l'attribution de valeurs primitives fonctionne) et la modification de l'adresse de a constn'est pas autorisée.

Là où, comme si le constpointait sur une valeur non primitive, il est possible de modifier la valeur de l'adresse.

Zyxmn
la source
1

J'ai parcouru cet article en cherchant pourquoi j'ai pu mettre à jour un objet même après l'avoir défini comme const . Le point ici est donc que ce n'est pas directement l'objet mais les attributs qu'il contient qui peuvent être mis à jour.

Par exemple, mon objet ressemble à:

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

Les réponses ci-dessus ont correctement souligné que c'est l'objet qui est const et non son attribut. Par conséquent, je pourrai mettre à jour l'identifiant ou le nom en faisant:

number.name = 'John';

Mais, je ne pourrai pas mettre à jour l'objet lui-même comme:

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

TypeError: Assignment to constant variable.
Atul O Holic
la source
1
votre exemple est pratique et des descriptions correctes
Ebrahim
0

Parce que dans const, vous pouvez modifier les valeurs d'un objet, afin que l'objet ne stocke pas réellement les données d'affectation, mais à la place, il pointe vers lui. il y a donc une différence entre les primitives et les objets en Javascript.


la source