Axel Rauschmayer 博士在Exploring ES6 中有const 定义:
const
和 let 一样工作,但是你声明的变量必须立即初始化,并带有一个以后不能改变的值。[…]
const bar = 123; bar = 456; // TypeError: `bar` is read-only
然后他写
const
仅意味着变量始终具有相同的值,但并不意味着该值本身是或变为不可变的。
我对这个陷阱有点困惑。任何人都可以清楚地定义const
这个陷阱吗?
Axel Rauschmayer 博士在Exploring ES6 中有const 定义:
const
和 let 一样工作,但是你声明的变量必须立即初始化,并带有一个以后不能改变的值。[…]
const bar = 123; bar = 456; // TypeError: `bar` is read-only
然后他写
const
仅意味着变量始终具有相同的值,但并不意味着该值本身是或变为不可变的。
我对这个陷阱有点困惑。任何人都可以清楚地定义const
这个陷阱吗?
当你const
在 JavaScript 中创建一些东西时,你不能重新分配变量本身来引用其他东西。但是,变量仍然可以引用可变对象。
const x = {a: 123};
// This is not allowed. This would reassign `x` itself to refer to a
// different object.
x = {b: 456};
// This, however, is allowed. This would mutate the object `x` refers to,
// but `x` itself hasn't been reassigned to refer to something else.
x.a = 456;
对于字符串和数字等基元,const
理解起来更简单,因为您不会改变值,而是为变量分配一个新值。
MDN总结得很好:
该
const
声明创建了一个对值的只读引用。这并不意味着它持有的值是不可变的,只是变量标识符不能重新分配。例如,如果内容是一个对象,这意味着对象本身仍然可以更改。
更简洁:const
创建一个不可变的绑定。
换句话说:const
,像var
,给你一个可变的内存块,你可以在其中存储一些东西。然而,const 规定你必须继续引用同一块内存——你不能将变量重新分配给不同的内存块,因为变量引用是常量。
要在声明之后真正使某些内容保持不变且不变,您需要使用类似Object.freeze()
. 但是,这是浅薄的,仅适用于键/值对。冻结整个对象需要更多的努力。以高效的方式重复执行此操作更具挑战性。如果你真的有这个需要,我建议你看看Immutable.js 之类的东西
const
和let
声明控制是否允许标识符和值之间的重新绑定(也称为重新分配):
const x = "initial value";
let y = "initial value";
// rebinding/reassignment
try { x = "reassignment" } catch(e) { console.log(x) } // fails
y = "reassignment"; // succeeds
console.log(y);
不变性是在类型级别控制的。Object
是可变类型,而String
是不可变类型:
const o = {mutable: true};
const x = "immutable";
// mutations
o.foo = true; // succeeds
x[0] = "I"; // fails
console.log(o); // {mutable: true, foo: true}
console.log(x); // immutable
首先,定义一下js中的值是什么。值可以是:布尔值、字符串、数字、对象、函数和未定义的值。
比如:人们用你的名字称呼你,它没有改变。然而,你换了衣服。在结合和人民之间,你是你的名字。其余的可以改变。对不起,奇怪的例子。
那么,让我给你举几个例子:
// boolean
const isItOn = true;
isItOn = false; // error
// number
const counter = 0;
counter++; // error
// string
const name = 'edison';
name = 'tesla'; // error
// objects
const fullname = {
name: 'albert',
lastname: 'einstein'
};
fullname = { // error
name: 'werner',
lastname: 'heisenberg'
};
// NOW LOOK AT THIS:
//
// works because, you didn't change the "value" of fullname
// you changed the value inside of it!
fullname.name = 'hermann';
const increase = aNumber => ++aNumber;
increase = aNumber => aNumber + 1; // error
// NOW LOOK AT THIS:
//
// no error because now you're not changing the value
// which is the decrease function itself. function is a
// value too.
let anotherNumber = 3;
const decrease = () => --anotherNumber;
anotherNumber = 10; // no error
decrease(); // outputs 9
const chaos = undefined;
chaos = 'let there be light' // error
const weird = NaN;
weird = 0 // error
如您所见,除非您没有将“第一个”分配的值更改为常量,否则不会出错。每当您尝试将第一个分配的值更改为其他值时,它就会生气,并给出错误。
因此,这是您在使用const
. 也就是说,它应该在其声明中初始化为一个值,否则它会生气。
const orphan; // error
const rich = 0; // no error
ES6
/ES2015
const
关键字:所述const
关键字被用于声明的块范围的变量(如使用声明let
)。使用const
和声明变量的区别let
如下:
const
不能重新赋值。const
必须在声明时赋值。这是上一点的逻辑结果,因为用 声明的变量不能重新分配,这就是为什么我们必须在声明变量时只分配一次。const
// we declare variable myVariable
let myVariable;
// first assignment
myVariable = 'First assingment';
// additional assignment
myVariable = 'Second assignment';
// we have to declare AND initialize the variable at the same time
const myConstant = 3.14;
// This will throw an error
myConstant = 12;
在上面的例子中,我们可以观察到以下内容:
myVariable
声明的变量let
可以先声明,然后再赋值。myConstant
声明的变量const
必须同时声明和赋值。myConstant
,会出现以下错误:未捕获的类型错误:赋值给常量变量
const
仍然是可变的:用const
just声明的变量不能重新赋值,它仍然是 mutable。可变意味着分配给const
变量的数据结构(对象、数组、映射等)仍然可以改变(即变异)。突变的例子是:
如果真的希望对象不可变,则必须使用类似Object.freeze()
. 这是一种冻结对象的方法。无法再更改冻结对象,也无法添加新属性。
const obj = {prop1: 1};
obj.prop1 = 2;
obj.prop2 = 2;
console.log(obj);
// We freeze the object here
Object.freeze(obj);
obj.prop1 = 5;
delete obj.prop2;
// The object was frozen and thus not mutated
console.log(obj);