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

为什么我可以在javascript中更改常量对象,javascript,ecmascript-6,constants,Javascript,Ecmascript 6,Constants,我知道ES6还没有标准化,而是JS中的const关键字 规范中规定: 常数的值不能通过重新赋值而改变,并且 无法重新声明常量。正因为如此,虽然 如果可以在不初始化的情况下声明常量,则 这样做没有用 当我这样做的时候: const xxx = 6; xxx = 999; xxx++; const yyy = []; yyy = 'string'; yyy = [15, 'a']; 我看到一切都很好,xxx仍然是6,yyy是[] 但是如果我做了yyy.push(6);yyy.推送(1),我的常量数

我知道ES6还没有标准化,而是JS中的
const
关键字

规范中规定:

常数的值不能通过重新赋值而改变,并且 无法重新声明常量。正因为如此,虽然 如果可以在不初始化的情况下声明常量,则 这样做没有用

当我这样做的时候:

const xxx = 6;
xxx = 999;
xxx++;
const yyy = [];
yyy = 'string';
yyy = [15, 'a'];
我看到一切都很好,
xxx
仍然是
6
yyy
[]

但是如果我做了
yyy.push(6);yyy.推送(1),我的常量数组已更改。现在它是
[6,1]
,顺便说一句,我仍然不能用
yyy=1来更改它


我这是一只虫子,还是我遗漏了什么?我在最新的chrome和FF29中试用了它,文档说明:

…常数不能通过重新赋值来更改
…无法重新声明常量

当您向数组或对象添加时,您没有重新分配或声明常量,它已经被声明和分配,您只是将其添加到常量指向的“列表”中

所以这很好:

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

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

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

const x = Object.freeze(['a'])
x.push('b')
console.log(x) // ["a"]

这与我能想到的每种编程语言都是一致的

假设C数组只是美化的指针。常量数组只意味着指针的值不会改变——但事实上,该地址包含的数据可以自由更改

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

你可以确信的是,常数总是指向同一个对象。对象本身的属性可以自由更改

const声明创建对值的只读引用。这并不意味着它所持有的值是不可变的,只是变量标识符不能被重新分配。例如,在内容是对象的情况下,这意味着可以更改对象的内容(例如,其参数)

此外,还有一个重要的注意事项:

全局常量不会成为窗口对象的属性


我想这会让你更清楚地了解这个问题:

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

const
指向包含原语值的地址时,您提到的
const
的定义将成立。这是因为在不更改其地址的情况下(因为这是分配原语值的工作方式),无法将值分配给该
常量
,并且不允许更改
常量
的地址


如果
常量
指向非原语值,则可以编辑地址的值

阅读本文时,我在搜索为什么我能够在将对象定义为
const
之后更新它。所以这里的要点是,它不是直接的对象,而是它所包含的可以更新的属性

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

const number = {
    id:5,
    name:'Bob'
};
上面的答案正确地指出,它是常量的对象,而不是它的属性。因此,我将能够通过执行以下操作来更新id或名称:

number.name = 'John';
但是,我将无法更新对象本身,如:

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

TypeError: Assignment to constant variable.

因为在常量中,可以更改对象的值,因此对象实际上并不存储赋值数据,而是指向赋值数据。
因此,Javascript中的原语和对象之间存在差异。

常量变量存储恒定的地址(内存地址,如0xFF2DFC)

常数不是内存中的内容

常量仅为内存地址


感谢阅读。

const
不会阻止修改复杂对象,如
数组
对象
。它只是防止重新分配或完全覆盖

例如:

如果是变量:

const xxx = 6;
xxx = 999; // error
此处不接受重新分配常量变量

如果是对象:

const person = {
  first_name: "John",
};
// reassigning the object
person = {
  first_name: "Michal", // error
};
// redeclear the object
const person = {
  first_name: "Michal", // error
};

// But:
person.last_name = "Doe"; // correct
输出:

console.log(person);
// Output => { first_name: "John", last_name: "Doe" }
console.log(days);
// output => [ "Sunday", "Monday" ]
如果是数组:

const days = ["Sunday"];

// reassigning array
days = ["Monday"]; // error

// redeclear array
const days = ["Monday"]; // error

// But

days.push("Monday"); // correct
输出:

console.log(person);
// Output => { first_name: "John", last_name: "Doe" }
console.log(days);
// output => [ "Sunday", "Monday" ]

你的意思是这不是一个bug,但它应该是这样工作的?因为我认为常数的概念是不能改变的。基本上,程序员相信无论发生什么事情,都不能改变常量中的值。我认为这并不容易,在这种情况下,常量的值是一个特定元素的数组。更改任何内容都意味着您更改了值。是的,它应该是这样工作的,您没有重新分配常量,它仍然是相同的引用,您只是将常量引用添加到数组中,数组和对象就像“列表”,修改它们不会更改引用或重新声明常量。@萨尔瓦多达利:常量和只读是两码事。您的变量是常量,但它指向的数组不是只读的。您可以创建一个类,声明变量并在类内赋值。然后,为该变量创建一个GETTER;不要恳求