原文链接:https://alligator.io/js/const-vs-obj-freeze/
使用对象最常用的目的是为了保持状态 - 例如配置数值或者你的应用要用到的常量。
它们通常是全局变量(这样就不再需要把它们作为函数参数传递),但全局变量是不安全的,因为它们可以被接收的函数所改变。我们来看看这个过程:
var canAlligatorsFly = false;
function isItFlying() {
canAlligatorsFly = true;
if (canAlligatorsFly) {
console.log("Yeah I'm flying");
}
isItFlying(); // Yeah I'm flying
函数isItFlying
接收全局变量并且可以将全局变量canAlligatorsFly
赋予一个新值,允许它们飞是一个糟糕的注意(译者注:指修改全局变量的值)。那我们应该如何避免变量被重新赋予新值?
这些情况的首选变量声明类型是const
。一旦const
变量在程序中被声明,它将阻止为这个变量重新赋值的行为。
const alligatorColor = "green";
function getMyColor() {
alligatorColor = "yellow"; // This part throws an error
return alligatorColor;
}
这里会抛出"类型错误:向常量分配值",const
已经使得alligatorColor
不可变。
还有别的情况吗? 我们来看看这个。
const reptiles = ['alligators', 'crocs'];
reptiles.push('snakes');
console.log(reptiles); // ['alligators', 'crocs', 'snakes']
看起来reptiles
中的值发生了变化。所以这意味着const
并不是使变量的值不可变,而是使变量的绑定不可变。这意味着不允许重新赋值变量,但const
变量引用的值仍然可能会发生变化。这就是为什么前面的例子中我们可以改变数组的值而不会触发类型错误
。
我们应该如何确认const
应用到对象的时候是绑定不可变而非值不可变?我们可以这样做:
const alligator = {
canItFly : false
};
alligator.canItFly = true;
console.log(alligator.canItFly); // true
现在我们知道在程序中使用全局变量来管理状态并不是很好的做法。我们需要让对象不受其属性变化的影响。
这就是Object.freeze()发挥作用的地方了。Object.freeze()防止修改或扩展对象的现有值。
let alligator = {
canItFly : false
};
Object.freeze(alligator);
alligator.canItFly = true;
console.log(alligator.canItFly); // false, the value is not modified
但请注意,Object.freeze允许这样赋值:
let alligator = {
canItFly : false
};
Object.freeze(alligator);
alligator = { pi: 3.14159 };
console.log(alligator) // {pi: 3.14159}
我们来总结一下:
const
使变量的绑定不可变但它的值是可以被修改的。Object.freeze()
忽略对对象的值修改,但对绑定没有限制。如果我们一起使用这两个会发生什么?
const alligator = {
canItFly : false
};
Object.freeze(alligator);
alligator.canItFly = true; // This is ignored
alligator = {pi: 3.14}; // This will throw an TypeError
console.log(alligator); // {canItFly: false}
上述的例子展示了const
和Object.freeze()
的联系,这是JavaScript中非常有用的程序设计。这将在我们稍后要学习的单例模式派上用场。