属性描述符
大约 2 分钟
属性描述符
获取和设置属性描述符
var obj = {
a: 1,
b: 2
}
// 获取属性描述符
const desc = Object.getOwnPropertyDescriptor(obj, 'a') // 这里获取 obj 的 a 属性的属性描述符
console.log(desc) // {value: 1, writable: true, enumerable: true, configurable: true}
/*
value: 属性的值
writable: 属性是否可以重写
enumerable: 属性是否可以遍历得到
configurable: 属性描述符本身是否可以修改
*/
// 设置属性描述符
Object.defineProperty(obj, 'a', {
value: 10,
writable: false,
enumerable: false,
configurable: false
})
obj.a = 20 // 不生效,因为上面设置了这个属性不能被重写
for (var key in obj) {
console.log(key) // 这里不会输出 a ,因为设置了这个属性无法通过遍历得到
}
Object.defineProperty(obj, 'a', {
writable: true // 不生效,因为上面设置了属性描述符本身无法被修改了
})
读取器(getter) 和设置器(setter)
属性描述符中有另外两个配置:get() 和 set()
,这两个配置就是读取器和设置器,他们的作用分别是读取属性的值和设置属性的值。
var obj = {}
var interanlValue = undefined
Object.defineProperty(obj, 'a', {
get: function() {
return interanlValue
},
set: function(val) {
interanlValue = val
}
})
console.log(obj.a) // undefined
obj.a = 1
console.log(obj.a) // 1
使用 getter 和 setter 编写一个更加牢固的构造函数:
var obj = {
a: undefined,
b: undefined
}
class NewObj {
constructor(obj) {
Object.defineProperty(this, 'data', {
get: function() {
return obj
},
set: function() {
throw new Error('data 属性是只读的,无法进行修改')
},
configurable: false,
})
let interanlText = undefined // text 属性赋值时的暂存变量
Object.defineProperty(this, 'text', {
get: function() {
return interanlText
},
set: function(val) {
// 这里也可以写一些限定条件(if判断)来限制该属性只能赋值为什么
interanlText = val
},
configurable: false,
})
}
}
var obj1 = new NewObj(obj)
console.log('obj1.data', obj1.data) // obj1.data { a: undefined, b: undefined }
console.log('obj1.text', obj1.text) // obj1.text undefined
obj1.text = 123
console.log('obj1.text', obj1.text) // obj1.text 123
obj1.data = 123 // Error: data 属性是只读的,无法进行修改
/*
上面这种写法虽然比较牢固,但是还是有其他的问题,如:
1、通过修改原始数据来修改:obj1.data.a = 123
防止的方法:使用 Object.freeze(obj) 来冻结数据,但是为了防止以后原始数据可能会有修改的需求,因此我们应该先将原始数据克隆,然后冻结克隆后的数据,如:`obj = { ...obj }; Object.freeze(obj)`
2、可以给 obj1 添加属性:如直接使用 obj1.newData = 'hhh'
防止的方法:在所有操作完成后,对自身进行冻结,Object.freeze(this)
3、在第二个问题的操作后,我们不光不能给 obj1 添加属性了,当 obj1 中有其他的属性时,其他属性也无法修改了
防止的方法:为了防止其他属性以后有修改的可能,我们可以将 Object.freeze(this) 替换为 Object.seal(this),对自身进行密封
4、通过原型修改数据:NewObj.prototype.haha = 'haha'
防止的方法:对原型进行冻结,Object.freeze(NewObj.prototype)
*/