AndreGeng / AndreGeng.github.io

blog repository
1 stars 0 forks source link

Object.preventExtension vs Object.seal vs Object.freeze #27

Open AndreGeng opened 5 years ago

AndreGeng commented 5 years ago

大家都知道用const声明的变量,只是保证变量的引用不会改变

const foo = [];
foo = 1; // Uncaught TypeError: Assignment to constant variable
foo.push(1); // foo: [1]

那有没有办法保证对象不对再添加新的属性呢? 答案是有的,而且还有不止一个,今天来对比下以下三个方法:

Object.seal()

const foo = {key1: 1};
Object.seal(foo);
foo.key2 = 2;
console.log(foo); // {key1: 1}
foo.key1 = 11;
console.log(foo); // {key1: 11}
console.log(Object.getOwnPropertyDescriptor(foo, 'key1')); // {value: 1, writable: true, enumerable: true, configurable: false}
delete foo.key1;
console.log(foo); // {key1: 11}
Object.getPrototypeOf(foo).key2 = 2;
console.log(foo.key2); // 2

它的作用如下:

  1. 可以防止本对象上新增属性。
  2. 原有属性configurable为false, aka, 不能删除原有属性,或者把原有属性变更为setter/getter。
  3. 仍可以在对象原型上新增属性。

Object.freeze()

const foo = {key1: 1};
Object.freeze(foo);
foo.key2 = 2;
console.log(foo); // {key1: 1}
foo.key1 = 11;
console.log(foo); // {key1: 1}
console.log(Object.getOwnPropertyDescriptor(foo, 'key1')); // {value: 1, writable: false, enumerable: true, configurable: false}
delete foo.key1;
console.log(foo); // {key1: 1}
Object.getPrototypeOf(foo).key2 = 2;
console.log(foo.key2); // 2

它的作用如下:

  1. 可以防止本对象上新增属性。
  2. 原有属性configurable为false, aka, 不能删除原有属性,或者把原有属性变更为setter/getter。writable也为false, 不允许更改原有属性的值。
  3. 仍可以在对象原型上新增属性。

ps: 这里的三个方法都只能保证“浅层”意义上的不可新增,要实现“深层”的immutable那只能,依次在嵌套的对象上递归调用这些方法了。