自发布以来,ES6为JavaScript带来了一些新特性和方法。这些新特性可以极大地改善我们开发人员的编码方式,提高生产力。今天我们来聊聊Object.freeze()
方法和const
。
有人认为这两个新特性在功能上重复了,其实不然。Object.freeze()
和const
的使用场景是有区别的,听我慢慢道来。
先来看看字面上的区别:
-
**const**
表现像let
。唯一的区别是,它定义的变量无法再次赋值。const
声明的变量具有块级作用域。它偏向于变量指向的内存地址不可变。 -
**Object.freeze()**
将一个对象作为参数,返回同一个对象的immutable
版本。这意味着我们希望不能添加,删除或更改此对象的任何属性。它偏向于对象不可变。
mutable对象具有可以更改的属性。immutable对象创建后便不可以更改属性。
可能光说内存地址不可变跟对象不可变还是有点抽象哈,我们来看几块代码就明白了。
来看个例子:
const
const user = 'zong'
user = 'jacob'
我们试图给使用const
关键字声明的变量user重新赋值,但这是一个无效的操作,会抛出一个Uncaught TypeError
异常。
只有var
或let
声明的变量才能重新赋值。
const的问题
当声明对象时,使用const仅防止再次赋值,但不保证不可变性(immutable),也就是不能防止更改其属性的值。
const
仅仅只能保证
const user = {
name: 'xxx'
}// won't work
我们无法对这个变量再次赋值。
但是我们可以修改这个对象本身,比如下面这段代码:
const user = {
name: 'zong',
email: 'hizong@xxx.com',
country: 'China',
}
user.last_name = 'jacob';
但这有时候并不是我们想要的,我们不希望我们的对象被修改,这时候 Object.freeze()
就派上用场了。
Object.freeze()
为了禁止对对象进行修改,我们需要使用 Object.freeze()
。
const user = {
name: 'zong',
email: 'hizong@xxx.com',
country: 'China',
}
Object.freeze(user)
user.name='xxx' //won't work
console.log(user)
Object.freeze()的问题
1.它是一个浅操作
要注意的是, Object.freeze()
是一个浅操作, 如果user某个属性是一个对象,那我们是需要递归地去应用它来确保整个user对象是不可修改的。
const user = {
name: 'zong',
contact: {
email: 'hi@xxx.com',
mobile: 000000,
}
}
Object.freeze(user);
user.name= 'jacob' //won't work
user.contact.telephone = 111111 //work
console.log(user)
所以当一个对象某个属性也是一个对象时,Object.freeze()
并没有完全freeze 一个对象。
要完全让一个对象不可变,我们得自己递归处理或者使用Deepfreeze或immutable-js这样的库。
2. 我们还可以对变量重新赋值
Object.freeze()
仅仅让传入它的对象immutable
,让我们无法修改它的属性,但是它没有规定我们不能修改变量指向的对象,也就是我们可以给变量重新赋值。
let user = {
name: 'zong',
contact: {
email: 'hi@xxx.com',
mobile: 000000,
}
}
Object.freeze(user);
console.log(user)
user={
name:'xxx'
}
console.log(user)
我们可以看到,如果我们用let
去声明了一个变量,尽管经过Object.freeze()
处理后,它指向的对象属性不可修改,但我们仍可以重新赋值。如果是const声明的变量,那就不行了。
到这儿我们就彻底搞清楚它们的区别啦,const
侧重于变量指向的内存地址不可变,Object.freeze()
侧重于生成的对象属性不可变。两者结合有可能实现一个内存地址,属性都不可变的对象。