ES6之属性描述符
一个对象除了属性名和属性值之外,还有一些额外的信息来描述属性,这就是属性描述符。
const obj = {
a: 1,
b: 2
}
Object.defineProperty(obj, "a", {
configurable: false,
value: 3,
enumerable: false
})
// Object.defineProperty(obj, "a", {
// value: 4,
// configurable: true
// })
for (const prop in obj) {
console.log(prop);
}
Object.defineProperties(obj, {
a: {},
b: {}
})
console.log(Object.keys(obj), Object.values(obj))
const desc = Object.getOwnPropertyDescriptor(obj, 'a')
console.log(desc)
可以通过 Object.getOwnPropertyDescriptor 来获取对象的属性描述符,或者是Object.getOwnPropertyDescriptors 来获取对象的所有属性描述符。value 为属性值,configurable 表示这个属性描述符是否可以被修改,enumerable 表示是否可以被枚举,也就是是否可以被一一罗列出来,writable 表示属性值是否可以被修改。如果不可以被枚举,就不可以使用 for-in 循环以及 keys 和 values 。
可以使用 Object.defineProperty 来设置属性描述符。第一个参数为对象,第二个参数为属性,第三个参数为要设置的属性描述符。也可以使用 Object.defineProperties 在里面设置属性。
const obj2 = {
name: "adsf",
age: 18
}
Object.defineProperty(obj2, 'age', {
get() {
console.log("getter")
return obj2._name;
},
set(val) {
if (typeof val !== "number") {
throw new TypeError("年龄必须为数字")
}
console.log("setter", val)
obj2._name = val;
}
})
obj2.name = "asdfasdf"
obj2.age = 10
console.log(obj2)
这里将属性描述符变成了函数运行的方式。当我们读取一个属性时,就会运行 get 函数,get 返回的值就为属性值。赋值一个属性时,就会运行 set 函数,并将等号右边的值传入 set 中。通过这种方式,我们可以灵活地控制属性的过程。这种属性叫做存取器属性。
如果在属性描述符里配置为存取器属性,则不能使用 value 和 writable 。因为存取器属性已经失去了内存空间,配置与内存相关的选项已经没有意义。
注意,我们不可以在里面使用相同功能的代码。比如在 get 中读取自己,在 set 中赋值自己,这样会不断触发自己,陷入无限递归。我们可以使用一个新的属性来代替,get 和 set 只是用来运行函数的,存放属性需要用其他的变量。
const user = {}
const spanName = document.getElementById("name")
Object.defineProperties(user, {
name: {
get() {
return spanName.innerText;
},
set(val) {
spanName.innerText = val;
}
}
})
通过这种方式,我们可以将 get , set 和元素绑定,只要对象的属性值变化和读取,都会触发页面元素的实时变化。一个元素里的许多属性都是存取器属性,只有在需要时才会重新读取,赋值,重新渲染。