Object.defineProperty(obj, prop, descriptor)
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
参数
- obj 目标对象
- prpo 属性值(目标对象存在该属性时,进行修改,不存在时进行创建)
- descriptor 对属性的描述,可选配置如下:
- configurable:默认值为false, 为true时,该属性的descriptor才能够被改变, 同时也能够被删除
- enumerable: 默认false, 为true时, 该属性才会出现再对象的枚举属性中
- value:属性值
- writable: false时,value值不可写
- get: 属性的 getter 函数,如没有则为 undefined,访问拦截器,
- set: 属性的 setter 函数,如果没有则为 undefined, 修改拦截器
在 get 和 set 方法中,this 指向某个被访问和修改属性的对
var obj = {};
obj.b = 1;
// 等同于:
Object.defineProperty(obj, "b", {
value: 1,
writable: true,
configurable: true,
enumerable: true
});
// 另一方面,
Object.defineProperty(obj, "a", { value : 2 });
// 等同于:
Object.defineProperty(obj, "a", {
value: 2,
writable: false,
configurable: false,
enumerable: false
});
// set get 方法
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function() {
console.log('get!');
return temperature;
},
set: function(value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function() { return archive; };
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
console.log(arc.getArchive()); // [{ val: 11 }, { val: 13 }]
vue2 实现双向绑定
Vue内部通过Object.defineProperty方法属性拦截的方式,把data对象里每个数据的读写转化成getter/setter,当数据变化时通知视图更新
/**
* 把一个对象的每一项都转化成可观测对象
* @param { Object } obj 对象
*/
function observable (obj) {
if (!obj || typeof obj !== 'object') {
return;
}
let keys = Object.keys(obj);
keys.forEach((key) =>{
defineReactive(obj,key,obj[key])
})
return obj;
}
/**
* 使一个对象转化成可观测对象
* @param { Object } obj 对象
* @param { String } key 对象的key
* @param { Any } val 对象的某个key的值
*/
function defineReactive (obj,key,val) {
Object.defineProperty(obj, key, {
get(){
console.log(`${key}属性被读取了`);
return val;
},
set(newVal){
console.log(`${key}属性被修改了`);
val = newVal;
}
})
}
let car = observable({
'brand':'BMW',
'price':3000
})
car.price; // price属性被读取了
car.price = 4000; // price属性被修改了
参考: