- 一、为什么需要使用Object.defineProperty?
- 二、使用步骤
- 1.简单使用
- 2.拦截器写法
- 3.模拟vue的数据劫持
- 总结
二、使用步骤 1.简单使用基础对象定义的属性,无法实现拦截器功能,使用Object.defineProperty定义的属性,可以增加拦截器,进而实现双向绑定
代码如下(示例):
// 通过Object.defineProperty定义属性,可以增加拦截器
let obj = {};
Object.defineProperty(obj, 'name', {
enumerable: true, // 是否可枚举(是否能访问),默认是false
configurable: true, // 是否可配置(删除),默认是false
writable: true, // 是否可以重写,默认false
value: 'hello',
});
obj.name = "world";
console.log(obj);
2.拦截器写法
代码如下(示例):
// 写法一:
let obj = {};
let other = void (0);
Object.defineProperty(obj, 'name', {
enumerable: true, // 是否可枚举(是否能访问),默认是false
configurable: true, // 是否可配置(删除),默认是false
get() {
console.log('读取属性');
return other;
},
set(val) {
console.log('设置属性');
other = val
}
});
obj.name = 'nihao'
console.log(obj.name); // nihao
// 写法二:
let obj = {
other: 'hello',
get name() {
return this.other;
},
set name(val) {
this.other = val;
}
};
obj.name = 'world';
console.log(obj.name); // world
3.模拟vue的数据劫持
// vue的数据劫持,其实就是将对象的所有属性通过Object.defineProperty变成响应式的
let data = {
name: {
first: '张',
last: '三'
},
age: '22'
}
function update() {
console.log('更新视图');
};
// 注意: Object.defineProperty只能识别对象,不能识别数组
function observer(obj) {
if (typeof obj !== 'object') return obj;
for (let key in obj) {
defineReactive(obj, key, obj[key]);
}
};
function defineReactive(obj, key, value) {
observer(value); // 如果内部属性还是对象,那么就再次执行,将内部属性变成响应式
Object.defineProperty(obj, key, {
get() {
return value;
},
set(val) {
if (val !== value) {
// 如果修改值的时候,直接将属性对应的对象赋值为另一个对象,那么需要在设置的时候调用一次,将赋值的新对象更改为响应式
observer(val);
// 每次获取的时候调一次更新视图的方法
update();
value = val;
}
}
})
}
observer(data);
// vue的数据劫持,其实就是将对象的所有属性通过Object.defineProperty变成响应式的
let data = {
name: {
first: '张',
last: '三'
},
age: '22'
}
function update() {
console.log('更新视图');
};
// 注意: Object.defineProperty只能识别对象,不能识别数组
function observer(obj) {
if (typeof obj !== 'object') return obj;
for (let key in obj) {
defineReactive(obj, key, obj[key]);
}
};
function defineReactive(obj, key, value) {
observer(value); // 如果内部属性还是对象,那么就再次执行,将内部属性变成响应式
Object.defineProperty(obj, key, {
get() {
return value;
},
set(val) {
if (val !== value) {
// 如果修改值的时候,直接将属性对应的对象赋值为另一个对象,那么需要在设置的时候调用一次,将赋值的新对象更改为响应式
observer(val);
// 每次获取的时候调一次更新视图的方法
update();
value = val;
}
}
})
}
observer(data);
data.name = ['李', '四'];
// 将常用的数组方法变为响应式的
let methods = ['push', 'pop', 'unshift', 'splice', 'split', 'reserve', 'sort'];
methods.forEach(method => {
// 装饰器,将原来的方法记录下来,在后面重新赋值
let oldMethod = Array.prototype[method];
Array.prototype[method] = function () {
update(); // 调用这些方法时重新赋值
oldMethod.call(this, ...arguments);
}
})
data.name.push('王');
data.name.push('五');
总结
本篇文章对Object.defineProperty进行总结,并实现简单版本的双向绑定



