为什么我可以在javascript中更改常量的值

时间:2014-05-02 20:30:08

标签: javascript ecmascript-6 const

我知道ES6尚未标准化,但JS中的lot of browsers currently support const关键字。

在规范中,写道:

  

常量的值不能通过重新赋值来改变,而a   常数不能重新申报。因此,尽管如此   如果没有初始化就可以声明一个常量,那就是   无用的。

当我做这样的事情时:

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

我发现一切正常xxx仍为6yyy[]

但如果我yyy.push(6); yyy.push(1);,我的常数数组已被更改。现在它是[6, 1],顺便说一下,我仍然无法用yyy = 1;更改它。

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

11 个答案:

答案 0 :(得分:106)

文档说明:

  

...常数不能通过重新分配来改变   ...常数不能重新声明

当您添加到数组或对象时,您没有重新分配或重新声明常量,它已经被声明和分配,您只需添加常量指向的“列表”。 / p>

所以这很好用

const x = {};

x.foo = 'bar';

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

和这个

const y = [];

y.push('foo');

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

但不是这些

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

答案 1 :(得分:24)

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

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

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

答案 2 :(得分:5)

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

考虑C - 数组只是美化指针。常量数组只表示指针的值不会改变 - 但实际上该地址包含的数据是免费的。

在javascript中,你可以调用常量对象的方法(当然 - 否则常量对象不会起到太多作用!)这些方法可能会产生修改对象的副作用。由于javascript中的数组是对象,因此这种行为也适用于它们。

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

答案 3 :(得分:2)

  

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

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

  

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

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

答案 4 :(得分:0)

我认为这将使您在以下问题上更加清楚:https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

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

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

好像const指向非原始值一样,可以编辑地址的值。

答案 5 :(得分:0)

在搜索为什么即使将对象定义为const后仍然能够更新对象时,请仔细阅读本文。因此,这里的要点是,它不是直接的Object而是它包含的可以更新的属性。

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

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

以上答案正确指出,是const对象而不是其属性。因此,我将可以通过以下操作来更新ID或名称:

number.name = 'John';

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

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

TypeError: Assignment to constant variable.

答案 6 :(得分:0)

因为您可以在const中更改对象的值,所以该对象实际上并不存储分配数据,而是指向它。 因此Javascript中的原语和对象之间是有区别的。

答案 7 :(得分:0)

const 变量存放的是常量的地址(内存地址如 0xFF2DFC)。

常量不是内存中的内容。

常量只是内存地址

感谢您的阅读。

答案 8 :(得分:0)

const 不会阻止诸如 arraysobjects 之类的复杂对象被修改。它只是防止重新分配或完全覆盖

示例:

In case of variable:

const xxx = 6;
xxx = 999; // error

这里不接受重新分配 const 变量。

In case of object:

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

Output:

console.log(person);
// Output => { first_name: "John", last_name: "Doe" }

In case of an array:

const days = ["Sunday"];

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

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

// But

days.push("Monday"); // correct

Output:

console.log(days);
// output => [ "Sunday", "Monday" ]

答案 9 :(得分:0)

const MY_OBJECT = {'key': 'value'};

// 试图覆盖对象抛出错误 // 未捕获的类型错误:赋值给常量变量。 MY_OBJECT = {'OTHER_KEY': 'value'};

// 但是,对象键不受保护, // 所以下面的语句执行没有问题 MY_OBJECT.key = 'otherValue'; // 使用 Object.freeze() 使对象不可变

// 同样适用于数组 const MY_ARRAY = []; // 可以将项目推入数组 MY_ARRAY.push('A'); // ["A"] // 但是,将新数组分配给变量会引发错误 // 未捕获的类型错误:赋值给常量变量。 MY_ARRAY = ['B'];

答案 10 :(得分:0)

关键字 const 有点误导。

它没有定义一个常数值。它定义了一个对值的常量引用。

因此你不能:

  • 重新分配一个常量值
  • 重新分配一个常量数组
  • 重新分配一个常量对象

但你可以:

  • 改变一个常量数组
  • 改变一个常量对象