对象增强
一、Object.defineProperty
属性都是直接定义在对象内部,或者直接添加到对象内部的
但是这样就不能对这个属性进行一些限制;比如属性是否可以通过 delete 删除,是否能在for in遍历的时候被遍历出来
如果想要对一个属性进行比较精准的操作控制,就可以使用属性描述符
- 通过属性描述符可以精准的添加或者修改对象的属性
- 属性描述符需要使用
Object.defineProperty来对属性进行添加或者修改
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
javascript
Object.defineProperty(obj, prop, descriptor)可接受三个参数:
- obj 是要定义属性的对象
- prop 是要定义或修改的属性名称或 Symbol
- descriptor 是要定义或修改的属性描述符
返回值
- 被传递给函数的对象
属性描述符的类型有两种:
- 数据属性描述符
- 存取属性描述符
二、数据属性描述符
数据属性描述符有四个特性:
[[Configuable]]: 表示属性是否可以通过 delete 删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符
- 当直接在对象上定义某个属性时,这个属性的 [[Configuable]] 为
true - 当通过属性描述符定义一个属性时,这个属性的 [[Configuable]] 为
false
javascriptvar obj = { name: 'mocha', age: 18, } Object.defineProperty(obj, 'name', { configurable: false, // 告诉js引擎,obj对象的name属性不可以被删除 }) delete obj.name console.log(obj) // { name: 'mocha', age: 18 } // 通过 Object.defineProperty 添加一个新的属性 Object.defineProperty(obj, 'address', {}) delete obj.address console.log(obj) // { name: 'mocha', age: 18 }- 当直接在对象上定义某个属性时,这个属性的 [[Configuable]] 为
[[Enumerable]]: 表示属性是否可以通过
for-in或者Object.keys()返回该属性- 当直接在对象上定义某个属性时,这个属性的 [[Enumerable]] 为
true - 当通过属性描述符定义一个属性时,这个属性的 [[Enumerable]] 为
false
javascriptvar obj = { name: 'mocha', age: 18, } Object.defineProperty(obj, 'name', { enumerable: false, }) const keys = Object.keys(obj) console.log(keys) // age- 当直接在对象上定义某个属性时,这个属性的 [[Enumerable]] 为
[[Writable]]: 表示是否可以修改属性的值
- 当直接在对象上定义某个属性时,这个属性的**[[Writable]]** 为
true - 当直接通过属性描述符定义属性时,这个属性的**[[Writable]]** 为
false
javascriptvar obj = { name: 'mocha', age: 18, } Object.defineProperty(obj, 'name', { writable: false, }) obj.name = 'latte' console.log(obj.name) // mocha- 当直接在对象上定义某个属性时,这个属性的**[[Writable]]** 为
[[value]]: 属性的 value 值,读取属性时会返回该值,修改属性时,会对其进行修改
- 默认情况下这个值是 undefined
javascriptvar obj = {} Object.defineProperty(obj, 'name', { configurable: false, enumerable: false, writable: false, value: 'mocha', }) console.log(obj.name) // mocha
三、存取属性描述符
存取属性描述符有四个特性:
- [[Configuable]]: 表示属性是否可以通过 delete 删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性
- 和数据属性描述符一致
- 当直接在对象上定义某个属性时,这个属性的 [[Configuable]] 为
true - 当通过属性描述符定义一个属性时,这个属性的 [[Configuable]] 为
false
- [[Enumerable]]: 表示属性是否可以通过
for-in或者Object.keys()返回该属性- 和数据属性描述符一致
- 当直接在对象上定义某个属性时,这个属性的 [[Enumerable]] 为
true - 当通过属性描述符定义一个属性时,这个属性的 [[Enumerable]] 为
false
- [[get]]: 获取属性时会执行的函数,默认为
undefined - [[set]]: 设置属性时会执行的函数,默认为
undefined
javascript
var obj = {}
var _name = ''
Object.defineProperty(obj, 'name', {
configurable: true,
enumerable: false,
set: function (value) {
console.log('set方法被调用了', value)
_name = value
},
get: function () {
console.log('get方法被调用了')
return _name
},
})
obj.name = 'mocha' // 赋值后set函数被执行:set方法被调用了 mocha
obj.name = 'latte' // 赋值后set函数被执行:set方法被调用了 latte
console.log(obj.name) // get方法被调用了 latte四、Object.defineProperties
Object.defineProperties() 方法直接在对象上定义多个新的属性或者修改现有属性,并且返回该对象
javascript
var obj = {
_age: 18,
}
Object.defineProperties(obj, {
name: {
writable: true,
value: 'mocha',
},
age: {
get: function () {
return this._age
},
},
})五、对象的其他方法补充
获取对象的属性描述符
getOwnPropertyDescriptor
javascriptvar obj = { name: 'mocha', age: 18, } console.log(Object.getOwnPropertyDescriptor(obj, 'name'))
getOwnPropertyDescriptors
javascriptvar obj = { name: 'mocha', age: 18, } console.log(Object.getOwnPropertyDescriptors(obj))
禁止对象扩展新属性:preventExtensions
给对象添加新的属性会失败(在严格模式下会报错)
javascriptvar obj = { name: 'mocha', age: 18, } Object.preventExtensions(obj) obj.address = '广州市' console.log(obj) // { name: 'mocha', age: 18 }
密封对象,不允许配置和删除属性:seal
实际是调用preventExtensions
并且将现有属性的configurable设置为
falsejavascriptvar obj = { name: 'mocha', age: 18, } Object.seal(obj) delete obj.name console.log(obj) // { name: 'mocha', age: 18 }
冻结对象,不允许修改现有属性:freeze
实际上是调用seal
并且将现有属性的writable设置为
falsejavascriptvar obj = { name: 'mocha', age: 18, } Object.freeze(obj) obj.name = 'latte' console.log(obj) // { name: 'mocha', age: 18 }