为什么我可以在javascript中更改常量对象
我知道ES6还没有标准化,而是JS中的为什么我可以在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),我的常量数
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;不要恳求