本篇文章总结控制对象访问的相关 API。
Object.defineProperty
Object.defineProperty 可以对对象的属性进行配置,它接收如下参数:
- obj:对象
- prop:属性
- descriptor:属性描述符
其中 descriptor 包括如下配置选项
- value:属性的值
- writable:属性是否可写,默认为- false
- set:为属性设置值时会触发此方法,设置的新值会作为参数传入
- get:访问此属性是会触发此方法
- configurable:该属性是否可再次进行配置,默认为- false
- enumerable:是否可遍历,默认为- false
其中 value 与 writable 是一组,set 和 get 是一组,二者不可同时使用。
例子1
| const obj = {} | 
在上面我们为 obj 的 name 属性配置了 value 属性为 Alice 作为 obj.name 的初始值,又配置了 writable 为 false,表明该属性是不可写的,对该属性进行赋值时无效的。
例子2
| const obj = {} | 
上面我们为 obj 的 name 属性配置了 set 和 get 方法,没当我们为 obj.name 赋予新值时都会调用 set 方法,并将新值传入,在 set 方法中,我们对新值进行了判断,如果新值为 Alice 则我们赋值给 username;每次当我们访问 obj.name 时,则会触发 get 方法,在 get 方法中我们直接返回了 username 这个变量的值,通过这种方式可以控制对象属性的访问操作。
例子3
| const obj = { | 
在上面我们定义了一个 obj 对象,其中有 a, b 两个属性,默认都是可枚举的。通过 Object.keys 方法可以取得对象中所以可枚举的属性,这时它们都在返回的数组中;接着我们配置 a 为不可枚举,此时再次调用 Object.keys,此时 a 就不在返回的数组中了。
例子4
| const obj = { | 
上面我们配置了 a 为不可枚举,并且配置 configurable 为 false,然后接着我们又想配置属性 a 为可枚举的,但是会报错 TypeError: Cannot redefine property: a,这是因为我们配置 configurable 为 false,表示不可再次配置,当我们再次对属性 a 进行配置便会报错。
| const obj = { | 
Object.defineProperties
Object.defineProperties 每次只能配置对象的一个属性,而 Object.defineProperties 可以一次性配置对象的多个属性,它的语法如下:
| Object.defineProperties(obj, { | 
见下例:
| const obj = { | 
Object.preventExtensions
Object.preventExtions(obj) 可以使得对象 obj 不可扩展,即不能为对象添加新的属性
| const obj = { | 
上面我们将 obj 设置为不可扩展后试图添加新的属性,但是并没有成功。设置为不可扩展后,我们可以正常访问现有对象上的属性,以及更改和删除
| const obj = { | 
对象一旦变为不可扩展后,就一直是不可扩展的。通过 Object.isExtensible 方法可以判断一个对象是否是可扩展的
| const obj = { | 
Object.seal
seal 的意思是封印,Object.seal 比 Object.preventExtensiable 更近一步,被 seal 了的对象,除了变为不可扩展,还不可配置 configurable: false,属性不能被删除了以及属性不能被 Object,defineProperty 进行配置了
| const obj = { | 
但是我们还可以对象现有的属性进行更改的
| const obj = { | 
通过 Object.isSealed 可以判断对象是否被 seal 了
| const obj = {} | 
Object.freeze
freeze 是冻结的意思,它相对于 Object.seal 更进一步,不仅不可扩展,不可配置,对象的数据熟悉 writable  会被设置为  false
| const obj = { | 
但是如果有定义 set 方法的话,对象属性还是可以被修改的
| const obj = { | 
通过 Object.isFrozen 方法可以判断一个对象是否被 freeze 了
| const obj = {} | 
Proxy
Proxy 是 ES6 中的新特性,它可以为对象做一层代理,当用户通过代理访问对象时,代理可以拦截一些操作,例如为属性赋值,访问属性的值,从而控制对象的访问。Proxy 可以拦截 13 种操作,这里不会详细介绍,只会介绍 set 和 get 拦截。
Proxy 的语法如下
| const proxy = new Proxy(target, { | 
例子1
| const target = { | 
上面我们为 target 对象做了层代理,当我们通过代理赋值时,会被 set 方法拦截,set 方法接收四个参数:
- trapTarget:被代理的对象
- key:被赋值的属性
- value:被赋的值
- receiver:操作发生的对象,即代理对象
上面我们只允许对 age 属性赋值,并且赋的值不能大于 18。
例子2
| const target = { | 
我们对 target 的 get 方法进行了代理,当我们通过代理对象访问属性值时,如果访问的是 age 属性,则返回 18,其他属性不做处理直接返回原值。
如果直接通过
target访问属性的话,操作是不会被拦截的,代理没有作用。
参考文献
- Object.defineProperty
- Proxy和Relect
- 《JavaSCript高级程序设计》,第三版







