1.vue2.x的响应式
实现原理:
对象类型:通过
Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data, 'count', { get () {}, set () {} })
存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
2.Vue3.0的响应式
实现原理:
通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
通过Reflect(反射): 对源对象的属性进行操作。
MDN文档中描述的Proxy与Reflect:
new Proxy(data, {
// 拦截读取属性值
get (target, prop) {
return Reflect.get(target, prop)
},
// 拦截设置属性值或添加新属性
set (target, prop, value) {
return Reflect.set(target, prop, value)
},
// 拦截删除属性
deleteProperty (target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
proxy.name = 'tom'
var person = {
name: "张三",
age: 12
}
var proxy = new Proxy(person, {
get(target, attr) {
console.log("获取属性时触发!")
// return "哈哈哈"
// return target[attr];
return Reflect.get(target, attr);
},
set(target, attr, value) {
console.log("触发了set");
//target[attr] = value;
return Reflect.set(target, attr, value);
},
deleteProperty(target, attr) {
console.log("删除了属性")
//delete target[attr];
return Reflect.deleteProperty(target, attr)
}
})
console.log(proxy.name);
proxy.name = "李四"
delete proxy.age
console.log(proxy);
var obj = {
name: "李四"
}
//重复性添加属性会报错
// try {
// Object.defineProperty(obj, "title", {
// get() {
// return "欢迎访问!!"
// }
// })
// Object.defineProperty(obj, "title", {
// get() {
// return "欢迎访问!!"
// }
// })
// } catch (error) {
// console.log(error)
// }
const result1 = Reflect.defineProperty(obj, "title", {
get() {
return "欢迎访问!!"
}
})
const result2 = Reflect.defineProperty(obj, "title", {
get() {
return "欢迎访问!!"
}
})
console.log(result1, result2) //true false
if (result2) {
console.log("下面要执行的语句!!")
} else {
console.log("代码错误!!")
}
reflect存在的意义:
1,将object对象一些内部的方法,放到Reflect对象上。比如:object.defineProperty
说明:现阶段这些方法存在于object和Reflect对象上,未来只存在于Reflect对象上。
意义:也就是说,从Reflect对象上可以拿到语言内部的方法。
2,操作对象时出现报错返回false
说明:比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
// 老写法
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}
// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
3,让操作对象的编程变为函数式编程
说明:老写法有的是命令式编程,比如下面这个例子
// 老写法
'assign' in Object // true
// 新写法
Reflect.has(Object, 'assign') // true
4,保持和proxy对象的方法一一对应
说明:Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。
Proxy(target, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target, name, value, receiver);
if (success) {
console.log('property ' + name + ' on ' + target + ' set to ' + value);
}
return success;
}
});
总结:综上所述,Reflect对象有4个意义:
(1)从Reflect对象上可以拿到语言内部的方法。
(2)操作对象出现报错时返回false
(3)让操作对象都变为函数式编程
(4)保持和proxy对象的方法一一对象