Object.defineProperty() 可以用来给对象添加属性,并控制对属性的访问操作。在我们访问或者修改某个对象的某个属性的时候,可以然后进行额外的操作。
Object.defineProperty 总览
首先,一个普通的对象是由多个名/值对组成的无序集合。对象中每个属性对于任意类型的值。例如:
const obj = {
name: '孩子',
age: 10,
run: function() {
console.log('Run');
}
};
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
基本语法:
Object.defineProperty(obj, prop, descriptor);
实例:
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// throws an error in strict mode
console.log(object1.property1);
// expected output: 42
参数
- obj: 要定义属性的对象。
- prop: 要定义或修改的属性的名称或。
- descriptor: 要定义或修改的属性描述符。。
第一个参数obj 和 prop参数很容易理解,重点说第三个参数
descriptor由两部分组成,数据描述符和访问器描述符,
- 数据描述符的含义是:它是一个包含属性的值,并说明这个属性值是可读或不可读的对象。
- 访问器描述符的含义是:包含该属性的一对 getter/setter方法的对象。
描述符可拥有的键值
数据描述符configurable enumerable value writable
存取描述符configurable enumerable get set
描述符默认值
- 拥有布尔值的键
configurable
、enumerable
和writable
的默认值都是false
。 - 属性值和函数的键
value
、get
和set
字段的默认值为undefined
。
返回值
被传递给函数的对象。
描述
该方法允许精确地添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,在枚举对象属性时会被枚举到(for...in
或 [Object.keys
])方,可以改变这些属性的值,也可以[删除
]这些属性。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty()
添加的属性值是不可修改(immutable)的。
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。
使用
添加普通属性
const obj = {};
let initValue = 'init';
Object.defineProperty(obj, 'name', {
// 当我们使用 obj.name 获取该值的时候,会自动调用 get 函数
get: function() {
console.log("custom-get")
return initValue;
},
set: function(value) {
console.log("custom-set " + value)
initValue = value;
}
});
console.log(obj.name); //获取值, 会调用get方法
obj.name = 'changeValue'; // 设置值,会调用set方法。
console.log(obj.name); // 获取值, 会调用get方法
添加数组属性
const obj = {};
let initValue = [];
Object.defineProperty(obj, 'array', {
set: function(value) {
console.log('set called' + JSON.stringify(value));
initValue = value;
},
get: function() {
return initValue;
}
});
console.log(obj.array); //执行get方法
obj.name = []; // 执行set方法
obj.name = [1, 2, 3]; // 执行set方法
obj.name[0] = 11;// 【对数组中的某一项进行改变值,不执行set方法】
console.log(obj.array); // 执行get方法
obj.name.push(4); // 【使用push方法对 obj.name数组添加属性 不执行set方法】
obj.name.length = 5; // 不会执行set方法