Object.defineProperty方法
参考连接
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
这里所说的对象的属性其实是类似于java对象中的成员变量,Object.defineProperty() 方法不仅可以修改这些变量的值,同时可以修改这些变量的属性。类似于可以修改java对象Student中private name成员的访问权限为public一样。
1)用法
Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象。
prop:要定义或修改的属性的名称或 Symbol 。
descriptor:要定义或修改的属性描述符。
如我要向object1加入一个property1的变量。
var object1= {}
Object.defineProperty(object1, 'property1', {
value: 10
});
2)描述符descriptor
descriptor不仅可以设置变量value还可以设置另外5个属性:
1、configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
Object.defineProperty(object1, 'property1', {
configurable: false,
});
Object.defineProperty(object1, 'property1', {
configurable: true,
});
报错 Uncaught TypeError: Cannot redefine property: property1
当设置为false后,无法再使用Object.defineProperty修改(覆盖)property1的属性
2、enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
对象是可以通过for in遍历属性的
var object1 = {
property2: 10
};
for (key in object1) {
console.log(key);
}
设置enumerable为true
Object.defineProperty(object1, 'property1', {
enumerable: true,
});
3、writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
Object.defineProperty(object1, 'property1', {
value: 20,
writable: false,
configurable: true
});
object1.property1 = 10;
console.log(object1.property1);
Object.defineProperty(object1, 'property1', {
value: 30
});
console.log(object1.property1);
Object.defineProperty(object1, 'property1', {
writable: true
});
object1.property1 = 10;
console.log(object1.property1);
writable设置为false无法使用 = 赋值,但是还是能用Object.defineProperty()赋值。
4、get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
5、set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
Object.defineProperty(object1, 'property1', {
get: function () {
console.log('get');
},
set: function () {
console.log('set');
}
});
console.log('write object1 property1');
object1.property1 = 10;
console.log('get object1 property1 ' + object1.property1);
在修改property1的值时会触发set方法,在访问property1时会触发get方法
这里虽然设置了object1.property1 但是打印出来还是undefined
descriptor分为两种
1、数据描述符,只包含configurable、enumerable、value、writable
2、存取描述符,只包含configurable、enumerable、get、set
一个descriptor不能同时包含 (value、writable)和(get、set)不然会报错
那我提前设置好值呢
var object1 = {
property1: 20
};
Object.defineProperty(object1, 'property1', {
get: function () {
console.log('get');
},
set: function () {
console.log('set');
}
});
console.log('write object1 property1');
object1.property1 = 10;
console.log('get object1 property1 ' + object1.property1);
结果还是一样,通过object1.property1 = 20;这种方式设置属性相当于
Object.defineProperty(object1, 'property1', {
value: 20,
writable: true,
enumerable: true,
configurable: true
});
再调用Object.defineProperty方法会覆盖原descriptor。
拥有布尔值的键 configurable、enumerable 和 writable 的默认值都是 false。
属性值和函数的键 value、get 和 set 字段的默认值为 undefined。
3)这个set get有什么用呢
get方法可以有return语句,访问该变量会返回该值。
set 和 get 方法可以使用this, this一般情况下是指向object1的。
var a = 10;
Object.defineProperty(object1, 'property1', {
get: function () {
return a;
},
set: function () {
}
});
console.log(object1.property1);
a = 20;
console.log(object1.property1);
我们可以用这种方式把对象中的变量与外部变量绑定起来。在一些复杂的逻辑下,使用这这种方法可以使代码更加清晰简洁,甚至办到一些厉害的操作(像vue这种框架)