属性描述符

2020-05-13  本文已影响0人  BA_凌晨四点

属性描述符:它表达了一个属性的相关信息(元数据)(本质上是一个对象)

属性是存在于对象之中,我们知道,对象有属性名和属性值,除了这些之外,还有一些相关信息,比如可以枚举的,可修改的等等,我们称之为属性描述符。

1.数据属性:

就是平时定义对象属性那些,如:

const phone = {brand: '小米'}  //初始化的时候写的
phone.price = 3999;  //后来写的
phone.system = function(){console.log('MIUI');} //甚至是函数

通过Object.getOwnPropertyDescriptors(对象); //可以得到一个对象的所有属性描述符。
通过Object.getOwnPropertyDescriptor(对象, 属性名)
可以得到一个对象的某个属性的属性描述符,它包括:

value:属性值
configurable:该属性的描述符本身是否可以修改
enumerable:该属性是否可以被枚举
writable:该属性的值是否可以被重新赋值
Object.getOwnPropertyDescriptors(对象)可以得到某个对象的所有属性描述符
如果需要为某个对象添加属性时 或 修改属性时, 配置其属性描述符,可以使用下面的代码:

Object.defineProperty(对象, 属性名, 描述符);
Object.defineProperties(对象, 多个属性的描述符)

2.存取器属性:

属性描述符中,如果配置了 get 和 set 中的任何一个,则该属性,不再是一个普通属性,而变成了存取器属性。

get 和 set配置均为函数,如果一个属性是存取器属性,则读取该属性时,会运行get方法,将get方法得到的返回值作为属性值;如果给该属性赋值,则会运行set方法。

 const phone = {
    brand: '小米',
    price: 3999,
    system: 'MIUI',
}
Object.defineProperty(phone, 'price', {
    get() { //这里用了下速写函数的方式,即 get:function(){...}
        console.log('get!!');
    },
    set() {
        console.log('set!!');
    }
});
phone.price;  //调用了get方法
phone.price = 123;
console.log(price);  //undefined, 它只是调用了set方法,而set方法没返回任何东西。所以undefined

phone.price = price + 1;  //undefined + 1 == NaN;  先调用get方法,再调用set方法
console.log(phone.price); //undefined;  调用了get方法
图片.png

其实DOM元素很多属性都是存取器属性:
它们都没办法直接显示出来,要显示就要调用方法。。

const div = document.querySelector('div');
console.dir(div);  //将对象结构打印出来
图片.png

存取器属性最大的特点就是,不是像之前的属性一样放在内存空间里面,以前的变量啊属性啊都是放在内存空间里面的;
变成存取器属性后,没有一块专门的内存空间来放数据了。变成了运行属性调用get函数,给属性赋值调用set函数。
运行以下代码会直接卡死。。

Object.defineProperty(phone, 'price', {
    get() {
        console.log(this.price);  //栈溢出。。。
        return phone.price;  //递归了。。
    },
    set(val) {
        console.log('set!!', val);
        phone.price = val;  //递归了。。。
    }
});
phone.price = 666;

所以在get方法里面不要读取该属性本身,在set方法里面不要给该属性本身赋值。好歹你也加个_(下划线)。暗示:内部属性。

存取器属性最大的意义,在于可以控制属性的读取和赋值。

小demo:

小米10价格:<span>0</span>
<script>
    const span = document.querySelector('span');
    const phone = {
        brand: '小米',
        price: 3999,
    }
    Object.defineProperty(phone, 'price', {
        get() {
            return span.innerText;
        },
        set(val) {
            span.innerText = val;  //给DOM添加文本
        }
    });
    phone.price = 1998; //运行了set函数
</script>

注意:
写了get 或 set 就不能在defineProperty里面写 value 或 writable 了,

Object.defineProperty(phone, 'price', {
    value:123,  //直接报错
    get() {},
    set(val) {}
});

因为配置了get 或 set之后,它变成一个存取器属性,本身就没有内存空间来放数据,是调用一个函数。
而value 和 writable表示的是内存空间里面的数据。。矛盾了。

上一篇 下一篇

猜你喜欢

热点阅读