什么是属性描述符
无论使用字面量创建对象,还是通过new Object创建对象,或者通过类去创建对象都无法对对象的属性进行一些限制,比如是否可以被枚举,是否可以被delete删除,如果我们想对一个属性进行比较精准的控制,就需要使用到属性描述符。属性描述符需要使用Object.defineProperty来对象属性进行添加或者修改。
属性描述符分为两种:数据描述符(数据属性)和存取描述符(访问器属性)。
1. 数据描述符
数据描述符一般是指数据属性的描述符,一般我们所用到的属性都是数据属性,具有以下几种:
| 描述符 | 说明 |
|---|---|
| value | 该属性对应的值。 |
| writable | 当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为false。 |
| configurable | 当且仅当该属性的configurable为true时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为false。 |
| enumerable | 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为false。 |
2. 存取描述符
存取描述符一般为访问器属性的描述符,比如 getter函数和setter函数,具有以下几种:
| 描述符 | 说明 |
|---|---|
| get | 给属性提供getter的方法,如果没有getter则为undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象 |
| set | 给属性提供setter的方法,如果没有setter则为undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。 |
| configurable | 当且仅当该属性的configurable为true时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为false。 |
| enumerable | 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为false。 |
3. 获取属性描述符
我们可以通过Object.getOwnPropertyDescriptor()方法去获取属性描述符。
Object.getOwnPropertyDescriptor(obj,prop)
作用:获取目标对象身上目标属性的属性描述符。
参数:
- obj:目标对象。
- prop:目标属性。
返回值:目标属性的属性描述符。
let person = {
name: "于家宝",
_age: 18,
};
console.log(Object.getOwnPropertyDescriptor(person, "_age"));
4. 设置属性描述符
我们可以通过 Object.defineProperty()方法去配置属性的描述符。
Object.defineProperty(obj,prop,descriptor)
作用:在目标对象上定义或者修改一个属性,同时可以配置该属性的属性描述符。
参数:
- obj:目标对象。
- prop:要定义或者修改的属性。
- descriptor:是一个对象,存放着将要被配置的属性描述符。
返回值:目标对象。
let person = {
name: "于家宝",
};
Object.defineProperty(person, "job", {
value: "程序员",
});
console.log(person.job); // 程序员
注意:如果通过Object.defineProperty()定义的属性,如果只设置了value一个属性描述符,那么该属性是不可删除、不可修改、不可枚举的。因为除了value属性描述符以外,其他的writable,configurable,enumerable默认都是false。
let person = {
name: "于家宝",
age: 18,
};
Object.defineProperty(person, "job", {
value: "程序员", // 不配置writable,configurable,enumerable就都默认false
});
console.log(person.job); // 程序员
person.job = "前端工程师";
delete person.job;
console.log(person.job); // 程序员,不可修改不可删除
for (i in person) {
console.log(i); // name age 没有job 不可枚举
}
4.1 配置writable
配置writable为true以后该属性就可以修改了。
let person = {
name: "于家宝",
};
Object.defineProperty(person, "job", {
value: "程序员",
writable: true,
});
console.log(person.job); // 程序员
person.job = "前端工程师";
console.log(person.job); // 前端工程师
4.2 配置configurable
配置configurable为true以后该属性就可以修改了。
let person = {
name: "于家宝",
};
Object.defineProperty(person, "job", {
value: "程序员",
configurable: true,
});
console.log(person.job); // 程序员
delete person.job;
console.log(person.job); // undefined
注意:属性描述符configurable为true的时候,是可以修改该描述符configurable的,如果为false就无法修改该修饰符,这说明一旦configurable为false就是不可逆的。
举个例子:
先设置为true在改为false,属性不可以被删除。
let person = {
name: "于家宝",
};
Object.defineProperty(person, "job", {
value: "程序员",
configurable: true, // 先设置为true
});
Object.defineProperty(person, "job", {
value: "程序员",
configurable: false, // 再设置为false
});
console.log(person.job); // 程序员
delete person.job;
console.log(person.job); // 程序员 没有被删除,说明configurable修改为false成功了
先设置为false在改为true,后台报错。
let person = {
name: "于家宝",
};
Object.defineProperty(person, "job", {
value: "程序员",
configurable: false, // 先设置为false
});
Object.defineProperty(person, "job", {
value: "程序员",
configurable: true, // 再设置为true,直接报错,configurable为false的时候是不可以修改该属性描述符的
});
4.3 配置enumerable
配置enumerable为true以后该属性就可以枚举了。
let person = {
name: "于家宝",
age: 18,
};
Object.defineProperty(person, "job", {
value: "程序员",
enumerable: true,
});
for (i in person) {
console.log(i); // name age job
}
4.4 同时配置多个属性描述符
我们可以通过 Object.defineProperties()方法去设置属性的描述符。
Object.defineProperties(obj,props)
作用:在目标对象上定义或者修改一个或多个属性,可以同时配置属性的属性描述符。
参数:
- obj:目标对象。
- props:一个对象,每一个属性都是一个对象,键是要定义或者修改的属性,值是该属性的属性描述符。
返回值:目标对象。
let person = {
name: "于家宝",
age: 18,
};
Object.defineProperties(person, {
job: {
value: "程序员",
enumerable: true,
},
address: {
value: "南京",
enumerable: true,
},
});
for (i in person) {
console.log(i); // name age job address
}