ES6之属性描述符

133 阅读2分钟

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 和元素绑定,只要对象的属性值变化和读取,都会触发页面元素的实时变化。一个元素里的许多属性都是存取器属性,只有在需要时才会重新读取,赋值,重新渲染。