Javascript 进阶 7-2 物件属性不可写入?物件扩充的修改与调整

上一篇文章我们提到了针对物件个别属性进行调整的 Object.defineProperty 以及 Object.defineProperties。

这篇文章呢要介绍 3 种 方法来针对整个物件进行调整喔!

分别是

1.preventExtensions => 防止扩充

2.seal => 封装

3.Freeze => 冻结

那么下面的是我们的範例物件

var person = {    a: 1,    b: 2,    c: {}};

首先先让我们介绍

preventExtensions 防止扩充

如同字面上的意义,就是要防止物件进行属性的扩充(新增属性),但是删除或是重新赋予值都还是OK的~! 实际来看看怎么应用吧!

var person = {        a: 1,        b: 2,        c: {}    };// preventExtensionsObject.preventExtensions(person);// 针对物件是否可以被扩充进行检查,回传布林值console.log('是否可被扩充', Object.isExtensible(person));// 用于确认物件中特定的属性是甚么,回传物属性的4个特徵console.log('person物件的 a 属性特徵', Object.getOwnPropertyDescriptor(person, 'a'));// 调整属性person.a = 'a';// 新增属性person.d = 'd';// 巢状属性调整person.c.a = 'ca';// 调整特徵Object.defineProperty(person, 'a', {    configurable: false});// 删除属性delete person.b;// 结果console.log('person物件', person);console.log('person a 属性(尝试修改后)', Object.getOwnPropertyDescriptor(person, 'a'));

首先呢,我们利用 Object.preventExtensions(person); 对person这个物件进行防止扩充的动作。

所以我们可以利用 Object.isExtensible(person) 来检查他是否可以扩充,这边会回传布林值来确认是否可以被扩充。

同时,如果我们想要知道某个物件的某个属性的特徵的话,可以利用 Object.getOwnPropertyDescriptor(物件, 属性名称) 的方式来查看,就会回传一个物件包含该属性的4个特徵。

所以这边我们也可以在进行防止扩充的动作后检查看看任一个该物件的属性是否有被改变

再来就进行一连串的调整以及删除之后,把最后person物件以及person a 属性印出来看看。

那么结果就如同下面所示:

http://img2.58codes.com/2024/20121770GAXXRI8SMt.png

可以看到,因为执行了防止扩充的动作,所以是否可以被扩充的地方回传的是false。

而person物件的 a 属性特徵则照实显示,并且除了value以外其他三个都是true。

但经过一连串的修改以后可以发现,person物件中,a属性的值被赋予成字串a。

b属性成功被删除

c属性的巢状赋值有成功

person物件的 a 属性特徵其中configurable也成功被改为false。

唯独新增d属性是失败的。

所以就如同一开始所描述的,防止扩充的动作其实就是在防止属性的新增尔已。

那么我们继续来看~

seal 封装

seal 的效果是让物件的属性无法新增删除,也无法重新配置特徵。

但是可以调整前属性值(value)。

同时,物件预设加上preventExtensions。

我们一样贴上相同的程式码并且稍微做修改的动作

// Sealvar person = {        a: 1,        b: 2,        c: {}    };Object.seal(person);// 针对物件是否被封装进行检查,回传布林值console.log('是否可被扩充', Object.isSealed(person));// 用于确认物件中特定的属性是甚么,回传物属性的4个特徵console.log('person物件的 a 属性性质', Object.getOwnPropertyDescriptor(person, 'a'));// 调整属性person.a = 'a';// 新增属性person.d = 'd';// 巢状属性调整person.c.a = 'ca';// 调整特徵Object.defineProperty(person, 'a', {    writable: false});// 删除属性delete person.b;// 结果console.log('person物件', person);console.log('person a 属性(尝试修改后)', Object.getOwnPropertyDescriptor(person, 'a'));

结果如下:

http://img2.58codes.com/2024/20121770LY7W7KeevR.png

所以在执行了封装的动作之后,利用 Object.isSealed(person) 来检查是否被封装,当然就是true。

而你可以看到,还在还没进行属性的调整之前,a属性的特徵,configurable就已经是false了,这也符合一开始说的

=> seal 的效果是让物件的属性无法新增删除,也无法重新配置特徵。

b的属性也还存在着。

同时,无法重新配置特徵就代表,利用 Object.defineProperty 将a属性的 writable 改为false 也是不成功的,结果上也的确如此,a属性的 writable还是维持在true的结果。

d的属性还是无法被新增。

但巢状赋值的执行还是成功的,c属性的物件中还是有a属性对应 字串ca 的值。

而且a属性还是成功赋值成 字串a 的值。

以上就是关于 seal 的介绍。

Freeze 冻结

跟 seal 很像,freeze的物件无法新增删除、不可以调整前属性值(value),当然也也无法重新配置特徵。

同时,物件预设加上seal。

那我们就来看看程式码怎么运行吧!

// Freezevar person = {        a: 1,        b: 2,        c: {}    };Object.freeze(person);// 针对物件是否被冻结进行检查,回传布林值console.log('是否有被封装', Object.isFrozen(person));// 用于确认物件中特定的属性是甚么,回传物属性的4个特徵console.log('person物件的 a 属性性质', Object.getOwnPropertyDescriptor(person, 'a'));// 调整属性person.a = 'a';// 新增属性person.d = 'd';// 巢状属性调整person.c.a = 'ca';// 调整特徵Object.defineProperty(person, 'a', {    enumerable: false});// 删除属性delete person.b;// 结果console.log('person物件', person);console.log('person a 属性(尝试修改后)', Object.getOwnPropertyDescriptor(person, 'a'));

结果如下:

http://img2.58codes.com/2024/20121770Qc9teJws4l.png

你会发现怎么出错了!!

原因就在于因为person物件被freeze了,所以这时候再进行Object.defineProperty的话就会直接抱错,所以这边我们要记得先把Object.defineProperty给注解调才能在正常运行喔!

// 调整特徵// Object.defineProperty(person, 'a', {//     enumerable: false// });

注解后的结果:

http://img2.58codes.com/2024/20121770atQrShx44s.png

我们来看,利用 Object.isFrozen(person) 来检查是否有被冻结? 当然是 true。

再来a属性的值不能被重新赋值,并且在freeze之后,只能够被列举,writable以及configurable都是false。

当然b属性也无法被删除,d属性无法被新增。

但巢状赋值的c属性还是可以不受限制。

以上就是关于 freeze的介绍。

以上三个方法都要再强调一遍,跟之前介绍的Object.defineProperty不同,是针对整个物件进行设定,但无法针对物件中的物件(巢状物件)进行设定,要的话也是分别设定。

如果没有问题的话,就往下一篇文章迈进吧!汪汪~


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章