对于 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
语句每执行一次,看起来是重新再次进入这个作用域。但实际上,是创建一个新的作用域。