为什么我可以在 javascript 中更改常量对象

IT技术 javascript ecmascript-6 constants
2021-01-27 14:28:32

我知道 ES6 还没有标准化,但是目前很多浏览器都支持 constJS 中的关键字。

在规范中,它写道:

常量的值不能通过重新赋值而改变,常量也不能被重新声明。因此,虽然可以在不初始化的情况下声明常量,但这样做是没有用的。

当我做这样的事情时:

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

我看到一切正常xxx6yyy[]

但是如果我这样做了yyy.push(6); yyy.push(1);,我的常量数组就被改变了。现在是[6, 1]这样,顺便说一句,我仍然无法用yyy = 1;.

我这是一个错误,还是我错过了什么?我在最新的 chrome 和 FF29 中尝试过

6个回答

文档指出:

...常量不能通过重新赋值而改变
...常量不能被重新声明

当您添加到数组或对象时,您不会重新分配或重新声明常量,它已经声明和分配,您只是添加到常量指向的“列表”。

所以这很好用:

const x = {};

x.foo = 'bar';

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

x.foo = 'bar2';

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

还有这个:

const y = [];

y.push('foo');

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

y.unshift("foo2");

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

y.pop();

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

但这些都不是:

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
我认为这并不容易,在这种情况下,常量的值是特定元素的数组。改变任何东西都意味着你改变了value
2021-03-11 14:28:32
是的,它应该以这种方式工作,您没有重新分配常量,它仍然是相同的引用,您只是将常量引用添加到数组中,并且数组和对象就像“列表”,修改它们确实如此不要更改引用或重新声明常量。
2021-03-26 14:28:32
所以你的意思是这不是一个错误,但它应该这样工作?因为我认为常数的想法是它不能改变。基本上,程序员相信无论发生什么,都无法改变常量中的值。
2021-04-02 14:28:32
@SalvadorDali:常量只读是两种不同的东西。您的变量是常量,但它指向的数组不是只读的
2021-04-03 14:28:32

发生这种情况是因为您的常量实际上存储了数组引用当您将某些内容加入数组时,您不是在修改常量值,而是修改它指向的数组。如果您将一个对象分配给一个常量并尝试修改它的任何属性,也会发生同样的情况。

如果您想冻结数组或对象使其无法修改,您可以使用该Object.freeze方法,该方法已经是 ECMAScript 5 的一部分。

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]
按照同样的逻辑,five设置为 5的常量实际上并不具有 5 的值,它只是对数字 5 的引用。因此,如果我这样做了,five++我不会更改常量,只是更改它指向的数字。
2021-03-11 14:28:32
@Anthony 参考值仅适用于数组和对象,不适用于原始值
2021-04-06 14:28:32
@Anthony 在您的示例中,您正在更改变量five指向的数字(该变量five曾经是数字 5 的标签,现在它指向不同的数字:6)。在问题(和这个答案)的例子中,x总是指向同一个列表;如果x是 const 你不能让它指向不同的列表。唯一的区别是同一个列表可以增长或缩小;这仅适用于数组和对象,而不适用于基元。
2021-04-06 14:28:32

这是我能想到的每种编程语言的一致行为。

考虑 C - 数组只是美化的指针。常量数组仅意味着指针的值不会改变——但实际上包含在该地址的数据是自由的。

在 javascript 中,您可以调用常量对象的方法(当然——否则常量对象将没有多大用处!)这些方法可能具有修改对象的副作用。由于 javascript 中的数组是对象,因此这种行为也适用于它们。

您可以确信的是,常量将始终指向同一个对象。对象本身的属性可以自由更改。

在搜索为什么即使将对象定义为const. 所以这里的重点是它不是直接的对象,而是它包含的可以更新的属性。

例如,我的对象看起来像:

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

上面的答案正确地指出它是常量而不是它的属性的对象。因此,我将能够通过执行以下操作来更新 ID 或名称:

number.name = 'John';

但是,我将无法像这样更新对象本身:

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

TypeError: Assignment to constant variable.
你的例子是一个实用的和正确的描述
2021-04-08 14:28:32

我认为这会让您更清楚地了解这个问题:https : //codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

基本上它归结为const始终指向内存中的相同地址。您可以更改存储在该地址中的值,但也不能更改const指向的地址

constconst指向包含原始值的地址您提到的定义将成立这是因为您不能在const不更改其地址的情况下为其分配值(因为这是分配原始值的工作方式)并且const不允许更改 a 的地址

如果const指向非原始值,则可以编辑地址的值。

这是另一个初学者友好的解释,说明原始类型和对象如何保存在内存中以及它们随后的不同行为(从 2017 年开始有点过时,但对该主题的介绍非常好): youtube.com/watch?v=9ooYYRLdg_g
2021-04-09 14:28:32