对于 ECMAScript 2016 中引入的 let 和 const 关键字。 let 声明的是可变变量。也就是可以随意重新赋值
let name = 'yufei'; name = 'hero'; console.log( name ); // yufei
而 const 声明的变量是不可变的,也称之为 「 常量 」,我们不能再次给它们赋值
const name = 'yufei'; name = 'hero'; //
输出结果为
Uncaught TypeError: Assignment to constant variable.
ECMAScript 2016 规范相关说明
ECMAScript 2016 规范中对 const 的说明为
「 changing a const variable always throws a TypeError 」
常规情况下,改变一个不可变变量只有在严格模式 ( strict mode ) 模式下才会抛出异常,就像 SetMutableBinding (N,V,S) 所说明的那样。
但 const 声明采用的却一直是严格模式,也就是只要尝试更改其值就会抛出异常,就像 FunctionDeclarationInstantiation(func, argumentsList) 35.b.i.1. 所说明的那样
陷阱:const 让值变的不可变
虽然 const 声明的变量是不可变的,但这只是说明它的不能被重新赋值。但并不意味着它的值本身是不可变的。
例如,对于一个声明 const person = obj1 只是声明了 person 不能被赋值为 obj2、obj2 ... 。但 obj1 的状态是可以更改的,可以添加或删除属性,也可以为它的属性重新赋值
例如下面这么做是禁止的
const obj = {} obj = {}; // 重新赋值,不允许 TypeError
但下面这样却是可以的
const obj = {}; obj.prop = 123; console.log(obj.prop); // 123
如果我们想让 obj 也变得不可变更。那么就必须使用 Object.freeze( obj ); 来创建一个不可变对象值
const obj = Object.freeze({}); obj.prop = 123; // TypeError
陷阱二 :Object.freeze( obj ) 创建的对象是不可变的
Object.freeze( obj ) 就如同 const 一样,陷阱也一模一样。Object.freeze( obj ) 只能保证 obj 本身是不可变的,也就是不能添加/删除属性,也不能给属性重新赋值。但是,对于属性值的内容,却是可以变更的。
例如下面的代码,bar 属性是不可变更的
> const obj = Object.freeze({ foo: {} }); > obj.bar = 123 TypeError: Can't add property bar, object is not extensible > obj.foo = {} TypeError: Cannot assign to read only property 'foo' of #<Object>
但是,obj.foo 却是可变的
> obj.foo.qux = 'abc'; > obj.foo.qux 'abc'
for 循环中的 const
const 变量一旦创建,就不可能更改。但这条规矩也不适用于 for 语句这种可以重复进入的作用域。
function logArgs(...args) { for (const [index, elem] of args.entries()) { // (A) const message = index + '. ' + elem; // (B) console.log(message); } } logArgs('Hello', 'everyone'); // Output: // 0. Hello // 1. everyone
此代码中有两个 const 声明,在行 A 和行 B 中。在每次循环迭代期间,它们的常量具有不同的值
这是因为 for 语句每执行一次,看起来是重新再次进入这个作用域。但实际上,是创建一个新的作用域。