vue3为什么要用proxy实现双向数据绑定?
一:object.defineProperty的缺点:
1.因为es5的object.defineProperty无法监听对象属性的删除和添加
2.不能监听数组的变化,除了push/pop/shift/unshift/splice/spObject.definert/reverse,其他都不行
3.Object.defineProperty只能遍历对象属性直接修改(需要深拷贝进行修改)
二:proxy的优点:
1.直接监听对象而非属性
2.直接监听数组的变化
3.拦截的方式有很多种(有13种,set,get,has)
4.proxy返回一个新对象,可以操作新对象达到目的
三:proxy的缺点:
proxy有兼容性问题,不能用polyfill来兼容(polyfill主要抚平不同浏览器之间的对js实现的差异)
四:实现vue3双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div></div>
<script>
const toProxy = new WeakMap(); //存放的是代理后的对象
const toRaw = new WeakMap(); //存放的是代理前的对象
function trigger() {
console.log('触发视图更新')
}
function isObject(target) {
return typeof target === 'object' && target !== null;
}
function reactive(target) {
if (!isObject(target)) {
return target;
}
let proxy = toProxy.get(target)
// 如果代理表中已经存在了 就把这个结果返回
if (proxy) {
return proxy
}
// 如果这个对象已经被代理过了 就直接返回
if (toRaw.has(target)) {
return target;
}
const handlers = {
set(target, key, value, receiver) {
if (target.hasOwnProperty(key)) {
trigger()
}
return Reflect.set(target, key, value, receiver)
},
get(target, key, value, receiver) {
const res = Reflect.get(target, key, receiver)
if (isObject(target[key])) {
return reactive(res)
}
return res;
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key)
}
}
let observed = new Proxy(target, handlers)
toProxy.set(target, observed);
toRaw.set(observed, target)
return observed
}
let obj = {
name: '温小鹿',
arr: [1, 2, 3]
}
// let p = reactive(obj)
// p.name = 'jw'
// let arr = [1, 2 ,3];
// let p = reactive(arr)
// p.push(4);
// console.log(p)
let p = reactive(obj)
p = reactive(p)
p = reactive(p)
p.arr.push(4)
console.log(p)
</script>
</body>
</html>