Make Object cannot be modified

echosoar 原创发表于 2019/10/23 08:59:21
#javascript #preventExtensions #seal #freeze
我们有时候会向让一个Object对象作为一个常量,让它不能被修改。但是由于Object在js中引用对象,使用const关键字并就会有下面这种情况:
const obj = { name: 'test' };

obj.name = 'test2';
console.log(obj.name); // test2 修改成功了

obj.name2 = 'iamgy';
console.log(obj.name2); // iamgy 新增属性成功了

delete obj.name2;
console.log(obj.name2); // undefined 删除成功了
可以看到并没有什么卵用,不能阻止向object内添加、修改或者删除属性,那么这种情况下该怎么办呢?

一个复杂还有缺陷的方式

在js中 Object.defineProperty 这个方法可以设置一个对象属性的属性描述符,比如说将 configurable 改为 false,那么这个属性就不能被删除,将 writable 设置为 false,那么这个属性就不能被修改赋值。
let o = { name: 123 };
Object.defineProperty(o, 'name', { configurable: false });

delete o.name;
console.log(o); // {name: 123} 删除失败了

Object.defineProperty(o, 'name', { writable: false });
o.name = 234;
console.log(o); // {name: 123} 修改失败了
但是这种方式只能阻止删除或修改对象的某个属性,并不能阻止往对象上面添加属性,那么这个时候该怎么办呢?

内置方法让写代码更美好

Object方法提供了 freeze、seal和preventExtensions三个方法,能够很方便的阻止一个对象的修改操作。

preventExtensions

使用了这个方法,那么就无法向一个对象上面添加新的属性了,从而解决了上面的问题,但是它并不能阻止修改已有属性的值和删除已有属性。
let o = { name: 'iamgy' };
Object.preventExtensions(o);
Object.isExtensible(o); // return false

o.size = 2019;
console.log(o); // { name: 'iamgy' } 新增属性失败了

o.name = 'test';
console.log(o); // { name: 'test' } 修改成功了

delete o.name;
console.log(o); // { } 删除成功了

seal

seal方法比preventExtensions更厉害一点,就是它不仅能够阻止添加新的属性,也能阻止删除已有属性,当然,它并不能阻止修改已有属性的值。
let o = { name: 'iamgy' };
Object.seal(o);
Object.isSealed(o); // return true

o.size = 2019;
console.log(o); // { name: 'iamgy' } 新增属性失败了

o.name = 'test';
console.log(o); // { name: 'test' } 修改成功了

delete o.name;
console.log(o); // { name: 'test'  } 删除失败了

freeze

freeze就是终极武器了,既能阻止添加新的属性,也能阻止删除已有属性,还能阻止修改已有属性的值。
let o = { name: 'iamgy' };
Object.freeze(o);
Object.isFrozen(o); // return true

o.size = 2019;
console.log(o); // { name: 'iamgy' } 新增属性失败了

o.name = 'test';
console.log(o); // { name: 'iamgy' }  修改失败了

delete o.name;
console.log(o); // { name: 'iamgy' }  删除失败了
终极武器虽然有用,但是还有缺陷,就是只能冻结object第一层的属性,无法深层次冻结,要深层次冻结,那么只能一层层遍历去挨个冻结了。