前端进阶课程之对象属性特性详解

一. js中对象到底是什么?

首先,大家想象我们平时都使用了对象的哪些对象?

常见的可能就是创建对象,然后取值,设值,例子如下:
var obj = {
    name: 'aaa' //定义属性
}
obj.name = 'bbb'; //设置属性值
console.log(obj.name); //读取属性值
复制代码

那到底如何取值,设值,内部是如何实现的呢?这就是我们本节要详解的内容。

接下来先说说:属性特性

二: 属性特性是什么?

我们平时的说法是:创建一个对象,然后给对象设置多个属性和属性值(即key:value),那给对象设置的这些属性又有哪些特性呢?

  1. configurable: 是否可以delete删除属性,是否可以修改属性特性
  2. enumerable: 是否可通过for...in..循环访问属性
  3. writerable: 是否可以修改属性的值
  4. value: 即属性值就直接设置在value上

总结:前三者默认都为true,value默认为undefined

我们结合代码来看看:

var obj = {
    name: 'aaa'
};
console.log(Object.getOwnPropertyDescriptor(obj, 'name'));
//结果如下:
{value: "aaa", writable: true, enumerable: true, configurable: true}

说明:我们可以通过Object.getOwnPropertyDescriptor方法获取指定对象属性的属性特性
复制代码

清楚了什么是属性特性以后,接下来,我们就要学会如何去定义或者修改这些属性特性?

三. 定义或者修改属性特性

通过上面,我们知道了对象属性默认有什么特性,那么这些特性如何修改呢?以及这些特性有哪些作用?

核心方法:Ojbect.defineProperty(), 或者Object.defineProperties() 前者只能定义属性及其特性,后者可以同时定义多个属性及其特性

这里我们直接采用后者定义多个属性:
Object.defineProperties(obj, {
    name1: {
        value: 'aaa'
    },
    name2: {
        value: 'bbb',
        configurable: false
    },
    name3: {
        value: 'ccc',
        configurable: true,
        enumerable: false
    },
    name4: {
        value: 'ddd',
        configurable: true,
        enumerable: true,
        writable: false
    }
});
console.log(obj);//{name4: "ddd", name1: "aaa", name2: "bbb", name3: "ccc"}
复制代码
  1. 我们来看一下name1:
//这里只是设置了value默认值,其他三个属性都没设置,则其他三个属性特性为false。
console.log(Object.getOwnPropertyDescriptor(obj, 'name1'));
//{value: "aaa", writable: false, enumerable: false, configurable: false}

说明:我们使用defineProperties或者defineProperty定义属性的特性时,如果没写某属性特性,则定义后结果为false.
复制代码
  1. 然后是name2:
//设置configurable为false,表示无法用delete删除,且无法再修改其属性特性(不包括value特性,也就是说只要writable为true,则就可以修改value,configurable是控制其他三个特性是否可以修改)
console.log(Object.getOwnPropertyDescriptor(obj, 'name2'));
//{value: "bbb", writable: false, enumerable: false, configurable: false}

我们试一下:
delete obj.name2;
console.log(obj.name2);//此时无法删除name2属性
Object.defineProperty(obj, 'name2', {
    value: '111'
});//此时会报错,Cannot redefine property: name2
复制代码
  1. 然后是name3:
//设置enumerable为false,则无法使用for..in..遍历属性
console.log(Object.getOwnPropertyDescriptor(obj, 'name3'));
//{value: "ccc", writable: false, enumerable: false, configurable: true}

我们试一下:
for (let key in obj) {
    console.log(key); //结果只输出了一个name4,因为其他三个属性的enumerable特性为false。
}
复制代码
  1. 然后是name4:
//设置writable为false,表示无法修改value值
console.log(Object.getOwnPropertyDescriptor(obj, 'name4'));
//{value: "ddd", writable: false, enumerable: true, configurable: true}

我们试一下:
obj.name4 = '12313';
console.log(obj.name4); // 结果依然是ddd
复制代码

四:自定义getter/setter特性

平时我们只是通过【对象.属性】去访问和设置对象属性,其实访问就是通过访问器特性get去获取的,设置就是通过访问器特性set去设置

(说明:这里的访问器属性可以理解为和属性特性统一级别的特性,只不过作用不同,前者是定义访问对象属性的特性,后者是定义对象属性本身的特性)

var obj = {
    _name: ''//说明:以_开头定义的属性,一般只用于对象内部方法去访问。
};
Object.defineProperty(obj, 'name', {
    get: function () {
        return this._name
    },
    set: function (newName) {
        this._name = newName;
    }
})
obj.name = 'aaa';//其实内部间接调用了该属性的set方法
console.log(obj.name);//其实内部间接调用属性的get方法
//已上代码其他就是get/set方法默认的实现,

当然,如果我们想要去自定义get,set方法也可以,只需要把get/set的函数体改一下即可。
Object.defineProperty(obj, 'name', {
    get: function () {
        return 'aaa'
    },
    set: function (newName) {
        this._name = newName;
    }
})
obj.name = 'bbb';
console.log(obj.name);//aaa
obj.name = 'ccc';
console.log(obj.name);//aaa
此时不管怎么样去修改name属性,其结果都是aaa,因为我们修改了get方法的默认实现,写死了每次都会返回一个固定的aaa。

当然以上代码,只是为了说明我们平时设置获取对象属性的内部原理,一般不会进行修改get/set的默认实现。

复制代码

猜你喜欢

转载自juejin.im/post/5bed63eb6fb9a049e701adac