大家都熟悉Vue中依靠Object.defineProperty()
来进行数据劫持,他像一个拦截器一样监控着一个对象上属性的改变。但是并不能深度监测到对象属性的变化,虽然Vue重写了一些array的原型链上的方法,如push()
、shift()
等,Vue官方也提供了方法Vue.set( target, propertyName/index, value )
(target可以是数组也可以是对象)来解决这些问题,但是手动操作很不方便。
在Vue迎来3.0更新的时候,同样Vue将用proxy
来实现数据劫持,接下来介绍介绍proxy
有什么方便的地方吧。
proxy
语法如下
// const p = new Proxy(target, handler)
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
}
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
很显然proxy
相比Object.defineProperty()
可以拦截属性的添加了,proxy不仅仅只有get,set拦截操作
handler.getOwnPropertyDescriptor()
这些都可以很多方法操作进行拦截
同样Vue3.0在实现数据劫持的时候还用到了Reflect属性
与大多数全局对象不同,Reflect
不是一个构造函数。你不能将其与一个new运算符一起使用,或者将Reflect
对象作为一个函数来调用。Reflect
的所有属性和方法都是静态的(就像Math对象)。它可以修改一个对象的属性等。在这里不再赘述。
使用proxy
实现双向绑定
<div id="app">
<input type="text" id="input" />
<div>您输入的是: <span id="title"></span></div>
<button type="button" name="button" id="btn">添加到todolist</button>
<ul id="list"></ul>
</div>
const obj = {};
const input = document.getElementById("input");
const title = document.getElementById("title");
const newObj = new Proxy(obj, {
get: function(target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver) {
console.log(target, key, value, receiver);
if (key === "text") {
input.value = value;
title.innerHTML = value;
}
return Reflect.set(target, key, value, receiver);
}
});
input.addEventListener("keyup", function(e) {
newObj.text = e.target.value;
});