冻结对象的概念
如果我们定义一个常量,我们现在都会使用 es6 的 const。但是 const 对于引用数据类型,指的是变量对应的指针是常量,但是指针所指向的内容是可以变的,比如下例
const a = 1;
a = 2; // chrome报错:Uncaught TypeError: Assignment to constant variable.
const a = {aa: 1};
a.aa = 2;
console.log(a.aa); // 2
冻结对象,终极的效果是,每个值都不能修改,也不能被删除属性
冻结对象的作用
如果我们编写函数库的时候,特别有时候需要用 es6 的 export 出去一些新的对象,因为此时 es6 的 import/export 是引用,有时候你不希望你的调用者去改变对应的值,这时候就需要把对象冻住
手写冻结一个对象
直接修改 Object.defineProperty
const a = {aa: 1};
Object.defineProperty(a, 'aa', {
writable: false,
configurable: false
})
a.aa = 2;
a.bb = 3;
console.log(a);
delete a.aa;
console.log(a)
a 的打印是:
{
aa: 1,
bb: 3
}
所以实际上,Object.defineProperty 的 writable 只能将已经定义过的 key“冻住”,对应 key 的值不能修改。但对于新增的属性则无法冻结
Object.preventExtensions()
Object.preventExtentsions()让一个对象不可扩展,就是不能添加新的属性
const a = [1, 2, 3, {second: 11}];
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, 0));
Object.preventExtensions(a); // 开始锁定对象
a[4] = 4;
console.log(a)
console.log(Object.getOwnPropertyDescriptor(a, '1'));
console.log(Object.isExtensible(a));
delete a[0];
console.log(a);
输出如下:
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 1,
writable: true
}
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 2,
writable: true
}
false
[undefined, 2, 3, [object Object] {
second: 11
}]
由此可见,preventExtensions 可以阻止对象新增属性。但是原对象依旧可以改删其它原有属性,
seal
Object.seal 封闭一个对象,阻止添加新属性并将现有的属性标记为不可配置(效果就是可以更改值,但是不能删除该属性)。
const a = [1, 2, 3, {second: 11}];
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, 0));
Object.seal(a);
a[4] = 4;
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, '1'));
console.log(Object.isExtensible(a));
delete a[0];
console.log(a);
a[0] = 5;
console.log(a);
输出如下:
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 1,
writable: true
}
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: false,
enumerable: true,
value: 2,
writable: true
}
false
[1, 2, 3, [object Object] {
second: 11
}]
[1, 2, 3, [object Object] {
second: 11
}]
可以看到,configurable 已经变成了 false,说明是不可以删除的,后面的 delete 操作也是无效。但是,对象里面的值却是可以更改的
可以用过 Object.isSealed() 判断这个对象是否被 seal 过
freeze
Object.freese() 可以冻结一个对象,这个是完全冻结,不能添加新属性,不能删除已有属性,不能更改对象已有属性的可枚举性,可配置性,可写性以及不能修改属性的值。该对象的原型也不能被修改
const a = [1, 2, 3];
console.log(a);
Object.freeze(a);
a[0] = 4;
console.log(a)
输出如下
[1, 2, 3]
[1, 2, 3]
由此可见,对象里面的元素也是不可变的
再来试验,如果对应的 value 不是个简单数据类型呢,比如如下
const a = [1, 2, 3, {second: 11}];
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, 0));
Object.freeze(a);
a[4] = 4;
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, '1'));
console.log(Object.isExtensible(a));
delete a[0];
console.log(a);
输出如下
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 1,
writable: true
}
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: false,
enumerable: true,
value: 2,
writable: false
}
false
[1, 2, 3, [object Object] {
second: 11
}]
更多文章可以看我的博客,如有错误,欢迎指正