daily-interview / fe-interview

:smiley: 每日一道经典前端面试题,一起共同成长。
https://blog.csdn.net/u010494753
MIT License
173 stars 22 forks source link

如何让const定义的对象真正不可修改? #34

Open artdong opened 5 years ago

artdong commented 5 years ago

如何让const定义的对象真正不可修改?

artdong commented 5 years ago

const对象

对象是可以更改的!

const person = {name: 'zhangsan'};
person.age = 16;
console.log(person);  // {name: 'zhangsan', age: 16}

Object.freeze

此方法冻结一个对象。冻结的对象不能再更改;冻结对象会阻止向其添加新属性、删除现有属性、阻止更改现有属性的可枚举性、可配置性或可写性,并阻止现有属性的值改变。此外,冻结对象还可以防止其原型被更改。freeze()返回传入的同一对象。

const person = {name: 'zhangsan'};
Object.freeze(person);
person.age = 16;
console.log(person);  // {name: 'zhangsan'}
person.name = 'lisi';
console.log(person);  // {name: 'zhangsan'}

Object.freeze做了两件事情

(1)给对象设置,Object.preventExtension(person),禁止更改原型,禁止添加属性; (2)为对象的每一个属性设置,writable:false,禁止更改属性值; (3)为对象的每一个属性设置,configurable:false。禁止删除属性,禁止更改writable为true,禁止更改enumerable为false,禁止更改configuable为true。

注:

禁止添加属性,是Object.preventExtensions控制的,而禁止删除属性,是configuable:false控制的。

Object.seal

const person = {name: 'zhangsan'};
Object.seal(person);
person.age = 16;
console.log(person);  // {name: 'zhangsan'}
person.name = 'lisi';
console.log(person);  // {name: 'lisi'}

Object.seal做了两件事情

(1)给对象设置,Object.preventExtension(person),禁止更改原型,禁止添加属性; (2)为对象的每一个属性设置,configurable:false,禁止更改属性值。

与Object.freeze不同的是,Object.seal后的对象是可写的writable:true。

Object.defineProperties()

此方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改的。

const person= {};
console.log('person:', person);
// 默认不可删除,不可枚举,不可修改
Object.defineProperty(person, 'name', {
    value: 'zhangsan'
});
console.log('person默认值:', person);  // zhangsan
delete person.name;
console.log('person删除后:', person); // zhangsan
console.log('person枚举:', Object.keys(person));
person.name = 'lisi';
console.log('person修改后:', person); // zhangsan
// 不能重新定义,会报重复定义错误: Uncaught TypeError: Cannot redefine property: name
Object.defineProperty(person, 'name', {
    value: 'lisi'
});

自定义age属性,可修改、可枚举、可删除

// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(person, "age", {
  value : 20,  // 属性age 的初始化值是20
  writable : true,  // 可修改值内容
  enumerable : true, // 可枚举,默认 false
  configurable : true // 可删除,默认 false
});

deepFreeze

Object.freeze只能冻结对象的一级属性,二级属性乃至n级属性是无效的,可以使用递归来实现。

let deepFreeze= (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, i) => {
    if ( typeof obj[key] === 'object' ) {
      constantize( obj[key] );
    }
  });
};