继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

JavaScript对象的不可变性

倚天杖
关注TA
已关注
手记 323
粉丝 47
获赞 187

通过以下方式创建的对象默认是可配置的,可写的,可枚举的:

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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP