要修改属性的默认特性,就必须使用 Object.defineProperty()方法 ;在了解Object.defineProperty()之前,需要先明白对象属性的一些特性,明白了这些特性之后,对Object.defineProperty()的学习就会顺利很多了。
1. 属性的类型
ECMA-262 使用一些内部特性来描述属性的特征。这些特性是由为JavaScript 实现引擎的规范定义的。因此,开发者不能在 JavaScript 中直接访问这些特性。
属性分两种:数据属性和访问器属性。
1.1 数据属性
数据属性包含一个保存数据值的位置。值会从这个位置读取,也会写入到这个位置。数据属性有 4个特性描述它们的行为:
Configurable:表示属性是否可以通过 delete 删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。默认情况下,所有直接定义在对象上的属性的这个特性都是 true;
Enumerable:表示属性是否可以通过 for-in 循环返回。默认情况下,所有直接定义在对象上的属性的这个特性都是 true;
Writable: 表示属性的值是否可以被修改。默认情况下,所有直接定义在对象上的属性的这个特性都是 true;
Value:包含属性实际的值。这就是前面提到的那个读取和写入属性值的位置。这个特性的默认值为 undefined。
1.2 访问器属性
访问器属性不包含数据值。相反,它们包含一个获取(getter)函数和一个设置(setter)函数。在读取访问器属性时,会调用获取函数,这个函数的责任就是返回一个有效的值。在写入访问器属性时,会调用设置函数并传入新值,这个函数必须决定对数据做出什么修改。访问器属性有 4 个特性描述它们的行:
Configurable:表示属性是否可以通过 delete 删除并重新定义,是否可以修改它的特性,以及是否可以把它改为数据属性。默认情况下,所有直接定义在对象上的属性的这个特性都是 true;
Enumerable: 表示属性是否可以通过 for-in 循环返回。默认情况下,所有直接定义在对象上的属性的这个特性都是 true;
Get: 获取函数,在读取属性时调用。默认值为 undefined;
Set:设置函数,在写入属性时调用。默认值为 undefined。
2. Object.defineProperty()
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象;
语法: Object.defineProperty(object,prop,descript)
Object.defineProperty()接收三个参数:
object: 要添加或者修改属性的目标对象;
prop: 要定义或修改属性的名称;
descript: 是一个对象,里面是我们上述的对象属性的特性;
下面我们使用Object.defineProperty()分别演示数据属性和访问器属性;
注意:数据属性和访问器属性不能同时设置,也就是数据属性的writable和value不能和访问器属性的set和get同时设置,否则会报错。
3. Object.defineProperty设置数据属性
3.1 Configurable
注意: 如果该属性被定义为不可配置(false)之后,就不能再变回可配置的了,否则会报错。
const person = {
name: 'lc',
};
// 定义新属性
Object.defineProperty(person, "age", {
configurable: false, // configurable 设置为 false,意味着这个属性不能从对象上删除
value: 25 // 设置age的值,不设置的话默认为undefined 后续不再演示value
});
console.log(person.age); // 25
delete person.age; // 因为configurable设置为false,所以无法删除该属性
console.log(person.age); // 25
// 修改已有属性
Object.defineProperty(person, "name", {
configurable: false,
value: "小明"
});
console.log(person.name); // 小明 value属性将值修改
delete person.name; // 因为configurable设置为false,所以无法删除该属性
console.log(person.name); // 小明
3.2 Enumerable
const person = {
name: 'lc',
age: 20
};
Object.defineProperty(person, "age", {
enumerable: false // 设置为false表示不能通过 for-in 循环返回
});
for (const i in person) {
console.log(i);
}
// 结果: name
3.3 Writable
const person = {
name: "lc"
};
Object.defineProperty(person, "name", {
writable: false // 表示属性的值不可以被修改
});
console.log(person.name); // lc
person.name = "小明"; // 修改无效
console.log(person.name); // lc
3.4 注意
在调用 Object.defineProperty()时,configurable、enumerable 和 writable 的值如果不指定,则都默认为 false。
const person = {};
Object.defineProperty(person, "name", {});
//configurable、enumerable 和 writable 的值未指定,则都默认为 false。
4. Object.defineProperty设置访问器属性
Configurable 和 Enumerable和上述一样,这里不再演示。
4.1 Get、Set
get: 获取函数,在读取属性时调用。默认值为 undefined;
set: 设置函数,在写入属性时调用。默认值为 undefined。
const book = {
year_: 2022,
edition: 1
};
Object.defineProperty(book, "year", {
get() {
return this.year_;
},
set(newValue) {
if (newValue > 2022) {
this.year_ = newValue;
this.edition += newValue - 2022;
}
}
});
book.year = 2021;
console.log(book.edition); // 2
5. 定义多个属性Object.defineProperties()
在一个对象上同时定义多个属性的可能性是非常大的。为此,ECMAScript 提供了 Object.defineProperties()方法。这个方法可以通过多个描述符一次性定义多个属性。它接收两个参数:要为之添加或修改属性的对象和另一个描述符对象,其属性与要添加或修改的属性一一对应:
const book= {};
Object.defineProperties(person, {
year_: {
value: 2022
},
edition: {
value: 1
},
year: {
get() {
return this.year_;
},
set(newValue) {
if (newValue > 2022) {
this.year_ = newValue;
this.edition += newValue - 2022;
}
}
},
})
6. 读取属性的特性Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor()方法接收两个参数:属性所在的对象和要取得其描述符的属性名,返回值是一个对象:
const person = {
name: 'lc'
};
console.log(Object.getOwnPropertyDescriptor(person, "name"));
// { configurable: true, enumerable: true, value: "lc", writable: true }
7. 获取所有属性的特性 getOwnPropertyDescriptors()
ECMAScript 2017 新增了 Object.getOwnPropertyDescriptors()静态方法。这个方法实际上会在每个自有属性上调用 Object.getOwnPropertyDescriptor()并在一个新对象中返回它们:
const person = {
name: "lc",
age: 22
};
console.log(Object.getOwnPropertyDescriptors(person));
结果如下:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。