通过以下方式创建的对象默认是可配置的,可写的,可枚举的:
let person = {name:'noshower'};let obj = new Object(); obj.name = 'noshower';
如果希望属性或对象是不可变的,那么该如何做?
请继续阅读->
首先,什么是对象的属性?
在 Javascript 中, 属性 由一个字符串类型的“名字”(name)和一个“属性描述符”(property descriptor)对象构成。
其中,属性描述符由value
,writable
,get
,set
,configurable
,enumerable
这些属性当中的某些组成。
writable
决定是否可以修改属性的值configurable
决定了是否可以修改属性描述符或者删除属性set
如果访问器属性没有设置set,该属性不可写
其次,如何修改或设置属性的属性描述符
使用Object.defineProperty(obj, prop, descriptor)
,该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
举个例子:
var person = {};Object.defineProperty(person, "name", { configurable: false, writable: false, value: "noshower"}); person.name = 'wang';console.log(person.name); // 输出 noshower 严格模式下,会报错
上面的例子中,我们给person对象添加了一个新属性,并且将该属性设置为不可写,不可删除。
最后,如何查看对象属性的属性描述符?
Object.getOwnPropertyDescriptor(obj, prop)
,该方法返回指定对象上一个自有属性对应的属性描述符。
以上一个例子为例:
console.log(Object.getOwnPropertyDescriptor(person,'name')) //输出如下: { value: 'noshower', writable: false, enumerable: true, configurable: false }
注意:接下来要讲的所有方法创建的都是浅不变性,只会影响目标对象和它的直接属性,并不会引用对象。
举个例子:
let person = { favorite:['apple'] }Object.defineProperty(person,'favorite',{ writable:false}) person.favorite = [];console.log(person.favorite); //[ 'apple' ]person.favorite.push('orange');console.log(person.favorite); //[ 'apple', 'orange' ]
上面的例子中,尝试修改person.favorite的引用,不成功。修改person.favorite引用的数组的值,成功了。
限制对象可变现的几种方法
1. 对象常量
要使对象的某个属性为常量(即不可修改,不可删除,不可重新定义)
可以按照上面讲的使用Object.defineProperty
方法,将属性的属性描述符writable,configurable都设为false
2.禁止对象扩展
使用Object.preventExtensions()
方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
注意:不可扩展的对象,属性可能还能够被删除。
注意:Object.preventExtensions()仅阻止添加自身的属性。但属性仍然可以添加到对象原型。
举个例子:
let person = { name: 'noshower'}//使得person不可扩展Object.preventExtensions(person); person.age = 22;console.log(person.age); // undefined age属性没有被添加进来delete person.name;console.log(person.name); //undefined name属性被删除了
3. 密封对象
使用Object.seal()
方法密封一个对象,这个方法实际上会在一个现有对象上调用Object.preventExtensions并把所有自身现有属性标记为configurable:false
密封之后,这个对象不能添加属性,不能重新配置或者删除任何现有属性。
不会影响从原型链上继承的属性。但__proto__
属性的值也会不能修改。
举个例子:
let person = { name: 'noshower'}//密封personObject.seal(person);//添加age属性person.age=23;//输出name属性的属性描述符console.log(Object.getOwnPropertyDescriptor(person,'name'));// { value: 'noshower',writable: true, enumerable: true,configurable:false }console.log(person.age); // undefined 表明不可添加新属性delete person.name;console.log(person.name); // noshower 表明不可删除属性
4. 冻结对象
Object.freeze()
方法可以冻结一个对象。这个方法实际上会在一个现有对象上调用Object.seal()并把所有数据访问属性标记为writable:false,这样就无法修改它们了。
举个例子:
let person = { name: 'noshower'} //冻结person对象Object.freeze(person);console.log(Object.getOwnPropertyDescriptor(person,'name')); // { value: 'noshower',writable: false, enumerable: true,configurable:false }person.name='Jack';console.log(person.name); // noshower 表明属性不可修改
总结
控制一个对象的不可变性,有四个方法:Object.defineProperty
(或者Object.defineProperties
),Object.preventExtensions
,Object.seal
,Object.freeze
。
记住了:这些方法创造的都是浅不变性。
作者:我待前端如初恋
链接:https://www.jianshu.com/p/dbe0467bb5c4