常用 Object Api
常用 Object Api
Object.preventExtensions
preventExtensions
仅阻止添加自身的属性。
- 禁止扩展对象,给对象添加属性(如果采用
obj.age= '123'
的方式新增属性,虽然不会报错,但也不会生效),如果采用Object.defineProperty(obj, 'name', { value: 123 })
的方式新增一个属性就会抛出异常TypeError
; - 对对象的原型是可以进行任何操作的(将该对象的原型指向另外一个对象这种操作除外)。
obj.__proto__ = {}
, 如果进行这个操作也会抛出异常TypeError
; - 可以对属性进行删除,
delete obj.name === true
; Object.isExtensible(obj)
可以判断一个对象是否是可扩展的,常规方式新建的对象是可扩展的,比如:let obj = {}, Object.isExtensible(obj) === true
;
Object.seal
Object.seal()
就是在Object.preventExtensions()
的基础上,对该对象自身的所有属性遍历设置其configurable: false
, 也就是禁止配置该对象的属性。
-
禁止扩展对象,且禁止配置一个对象的属性;
-
对原有对象的属性的值进行修改是可以的,
Object.defineProperty(obj, 'name', { value: 333 })
或者obj.name=333
都可以; -
禁止
delete
一个对象的属性,delete obj.name === false
; -
需要注意的是,一个
configurable
为false
的属性, 其他配置属性都不可修改,但是可以Object.defineProperty(obj, 'name', { value: 333 })
可以通过这种方式修改value
,并且能够将writable
由true
变为false
,但是不能由false
变为true
; -
MDN描述如下,当
configurable
为false
时一个属性的行为;
Object.freeze
在
Object.preventExtensions
的基础上对该对象自身的所有属性遍历设置其writable: false,configurable: false
, 也就是禁止对该属性禁止赋值操作,并且禁止配置。
- 禁止扩展一个对象,也就是不能新建属性;
- 禁止将已存在属性更改值,
obj: { name: '123' }; obj.name = '234'
; - 禁止配置一个属性,
Object.defineProperty(obj, 'name', {...})
; - 禁止删除一个属性,
delete obj.name
; - 同样不影响对原型的操作,当然还是不允许将原型指向一个新的对象;
- 这里的冻结只是浅层次的冻结,
obj: { school: {} }; obj.school.name = 'aaa'
,这个操作是可以的,如果属性值是一个对象,而我们的更改不会影响这个对象的引用关系即可; - 冻结之后:
Object.isExtensible(obj) === fasle; Object.isSealed(obj) === true; Object.isFrozen(obj) === true
;
preventExtensible, seal, freeze 总结
这里我们可以发现Object.preventExtensible(); Object.seal(); Object.freeze()
的关系是层层递进的:
Object.preventExtensible()
禁止对象扩展,不影响对原型的操作,除了将原型指向新的对象;Object.seal()
在Object.preventExtensible()
的基础上,将该对象的属性的配置项(描述符):{ configurable: false }
设置为false,也就是禁止配置该属性;Object.freeze()
在Object.preventExtensible()
的基础上,将该对象将该对象的属性的配置项(描述符):{ configurable: false; writable: false }
,也就是禁止配置该属性,也禁止改写这个对象的属性的值;- 上面的操作都不影响对其原型的更改,除了将原型指向一个新的引用
obj.__proto__ = {}
;
补充:
- 通过
let obj = {}; Object.defineProperty(obj, 'age', { value: 18 })
配置一个属性的话,如果没有显示指定对象描述符的话,那么类似于{ configurable: false, writable: false, enumerable: false }
这些boolean
类型的描述符都是false
,也就是禁止配置更改和枚举; - 如果通过
let obj = {}; obj.age= 18
, 那么他的描述符是{ configurable: true, writable: true, enumerable: true}
这些boolean
类型的描述符都是true
,也就是可以配置更改和枚举; - 存取描述符
{ get(){}, set(){} }
和数据描述符中的{ writable: boolean, value: xxx }
是互斥了,这两组同时只能存在一组; - 关于
enumerable: boolean
,代表一个属性是否可以枚举,也就是是否可以被for...in; Object.keys()
等常规方式遍历出来;
Object.defineProperty
描述符默认值
- 拥有布尔值的键
configurable
、enumerable
和writable
的默认值都是false
; - 属性值和函数的键
value
、get
和set
字段的默认值为undefined
;
描述符的类别
-
存取描述符:
get, set
; -
数据描述符:
value, writable, enumerable, writable
;
其中 get, set
和 value, writable
不能同时存在。
注意点
当设置 configurable
为 false
的注意点:
由该图总结一下,当 configurable: false
时:
- 不能再接着用
Object.defineProperty
对其描述符进行变化性配置,也就是说如果和原来的配置相同,则没问题; - 有一个特殊的就是可以单向将
writable
改为false
,比如:writable: true --> false
,反过来则不可以;
当 writable: false
时:
- 对值的改变不会生效,但是也不会报错;