/*
1.Vue是如何实现实时监听数据变化的?
通过原生JS的 defineProperty 方法
2.defineProperty方法的特点
可以直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象
3.defineProperty用法
obj: 需要操作的对象
prop: 需要操作的属性
descriptor: 属性描述符
Object.defineProperty(obj, prop, descriptor)
*/
let obj = {};
// 需求: 给obj对象动态新增一个name属性,并且name属性的取值必须是abc
Object.defineProperty(obj, 'name', {
value: 'abc',
writable: true, // true 新增的属性值可修改。默认不可修改
configurable: true, // name属性是否可删除。默认不可删除
enumerable: true, // 新增的name属性是否可迭代遍历。默认不可
})
console.log(obj) // {name: "abc"}
// 默认不可删除新增的属性
delete obj.name
/*
3.1 defineProperty除了可以动态修改/新增对象的属性以外
还可以在修改/新增的时候给该属性添加get/set方法
3.2 get/set方法特点
只要通过defineProperty给某个属性添加了 get/set方法
那么以后只要获取这个属性的值就会自动调用get,设置了这个属性的值就会自动条用set
3.3注意点
如果设置了get/set方法,那么就不能通过value直接赋值,也不能设置writable: true
*/
let oldValue = "测试数据";
Object.defineProperty(obj, 'test', {
configurable: true,
enumerable: true,
get() {
return oldValue
},
set(newValue) {
if(oldValue !== newValue) {
oldValue = newValue;
}
}
})
// 需求:快速监听对象中所有属性的变化
let obj = {
name: 'ceshi',
age: 18
}
// 只要将需要监听的那个对象传递给Observer这个类
// 这个类就可以快速的给传入的对象的所有属性都添加get/set方法
class Observer {
constructor(data) {
this.observer(data); // constructor 方法是类的默认方法,创建类的实例化对象时被调用。
}
observer(obj) {
if(obj && typeof obj === 'object') {
// 遍历取出传入对象的所有属性, 给遍历到的属性都增加get/set方法
for(let key in obj) {
this.defineRecative(obj, key, obj[key])
}
}
}
// obj: 需要操作的对象
// attr: 需要新增get/set方法的属性
// value: 需要新增get/set方法属性的取值
defineRecative(obj, attr, value) {
// 如果属性的取值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
this.observer(value);
Object.defineProperty(obj, attr, {
get(){
return value;
},
set:(newValue)=>{
if(value !== newValue){
// 如果给属性赋值的新值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
this.observer(newValue);
value = newValue;
console.log('监听到数据的变化, 需要去更新UI');
}
}
})
}
}
new Observer(obj);
// obj.name = '123';
// obj.age = 23;
// obj.name.a = 'dtdgf';
obj.name = {a: 'abc'};
obj.name.a = '测试文本';