Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象;
该方法也是vue实现数据绑定和更新数据的核心代码之一。
Object.defineProperty(obj,prop,descriptor)
对象的属性描述符也是一个普通对象,主要有两种形式:数据描述符和存取描述符;
一个描述符只能是这两者其中之一;不能同时是两者
这两种描述符对象,共享以下两个键值(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):
例如:
var obj = {};
Object.defineProperty(obj,'fullName1',{
configurable:false,
value:1
})
Object.defineProperty(obj,'fullName2',{
configurable:true,
value:2
})
console.log(obj); // {fullName1: 1, fullName2: 2}
delete obj.fullName1;
delete obj.fullName2;
console.log(obj); // {fullName1: 1} fullName1属性没有被删除,fullName2属性被删除了
例如:
var obj = {};
Object.defineProperty(obj,'fullName1',{
configurable:true,
value:1,
enumerable:false
})
Object.defineProperty(obj,'fullName2',{
configurable:true,
value:2,
enumerable:true
})
console.log(Object.keys(obj)) // ['fullName2']
数据描述符具有以下两个特有可选键值:
例如:
var obj = {};
Object.defineProperty(obj,'fullName1',{
configurable:true,
value:1,
enumerable:false,
writable:false
})
Object.defineProperty(obj,'fullName2',{
configurable:true,
value:2,
enumerable:true,
writable:true
})
obj.fullName1 = 3;
obj.fullName2 = 4;
console.log(obj) // {fullName2: 4, fullName1: 1}
// 只有fullName2被修改了
存取描述符具有以下两个特有可选键值:
例如:
var obj = {};
Object.defineProperty(obj,'firstName',{
configurable:true,
enumerable:true,
value:'zhang'
})
Object.defineProperty(obj,'endName',{
configurable:true,
enumerable:true,
value:'san'
})
Object.defineProperty(obj,'fullName',{
configurable:true,
enumerable:true,
get(){
return this.endName+'.' +this.firstName;
}
})
console.log(obj.fullName); // san.zhang 当属性被访问时,才会调用函数
set
属性的 setter 函数,如果没有 setter,则为 undefined。**当属性值被修改时,会调用此函数。**该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
默认值:undefined。
例如:
var obj = {};
Object.defineProperty(obj,'firstName',{
configurable:true,
enumerable:true,
value:'zhang',
writable:true,
})
Object.defineProperty(obj,'endName',{
configurable:true,
enumerable:true,
value:'san',
writable:true
})
Object.defineProperty(obj,'fullName',{
configurable:true,
enumerable:true,
get(){
return this.endName+'.' +this.firstName;
},
set(value){
let temp = value.split('.');
console.log(temp)
this.endName = temp[0];
this.firstName = temp[1];
}
})
console.log('firstName:'+obj.firstName,'endName:'+obj.endName,'fullName:'+obj.fullName); // firstName:zhang endName:san fullName:san.zhang
obj.fullName = 'si.li';
console.log('firstName:'+obj.firstName,'endName:'+obj.endName,'fullName:'+obj.fullName); // firstName:li endName:si fullName:si.li
“如果一个描述符不具有 value、writable、get 和 set 中的任意一个键,那么它将被认为是一个数据描述符。如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常”
注意:
这些选项不一定是自身属性,也要考虑继承来的属性。为了确保在设置前,保留这些默认值,可以明确指定所有的选项值,或者通过Object.create(null) 将 __ proto__ 指向null。
例如:
// 使用 __proto__
var obj = {};
var descriptor = Object.create(null); // 没有继承的属性
// 默认没有 enumerable,没有 configurable,没有 writable
descriptor.value = 'static';
Object.defineProperty(obj, 'key', descriptor);
// 显式
Object.defineProperty(obj, "key", {
enumerable: false,
configurable: false,
writable: false,
value: "static"
});