vue2通过Object.defineProperty来实现双向绑定的。
代码如下:
<body>
<input id="text"></input>
<script>
// js数据
let obj = { jsText:'abc'};
let tempVal;
Object.defineProperty(obj,'jsText',{
// 监视设置和
set(newValue){
console.log('jsText被改变了',newValue);
// text.value = newValue;
tempVal = newValue;
// 更新页面的数据
text.value = newValue;
},
get() {// 获取
console.log('jsText被获取了');
return tempVal;
}
});
// 增加一个属性 无法察觉
obj.a = '111';
// 删除一个属性 无法察觉
delete obj.a;
text.oninput = function(e) { // 用户输入改变js内存
obj.jsText = e.target.value;
}
</script>
</body>
由于vue2不能察觉动态的添加和删除属性。只能通过$set去添加。$delete去删除。而vue3这次则做了升级。
vue3则是用ES6 Proxy 对象的属性及各种操作进行监控,支持添加以及删除
<body>
<script>
let obj = { text:'abc'};
// ES6 Proxy 对象的属性及各种操作进行监控
let proxy = new Proxy(obj,{
set(target,propKey,value){
target[propKey] = value;
console.log('set||add:',arguments);
return true;
},
get(target,propKey){
console.log('get:',arguments);
return target[propKey];
},
deleteProperty(target,propName) {
console.log('删除了')
}
});
// vue2不能察觉动态添加和删除属性
proxy.abc = '123';
delete proxy.abc;
</script>
</body>
proxy的api
<script>
let obj = {a:'xxx'};
let p = new Proxy(obj, {
get(target, propKey, receiver) {
console.log('get')
return Reflect.get(target, propKey)
},
set(target, propKey, value, receiver) {
console.log('set')
return Reflect.set(target, propKey, value)
},
has(target, propKey) {
console.log('has')
return Reflect.has(target, propKey)
},
deleteProperty(target, propKey) {
console.log('deleteProperty')
return Reflect.deleteProperty(target, propKey)
},
ownKeys(target) {
console.log('ownKeys')
return Reflect.ownKeys(target)
},
getOwnPropertyDescriptor(target, propKey) {
console.log('getOwnPropertyDescriptor')
return Reflect.getOwnPropertyDescriptor(target, propKey)
},
defineProperty(target, propKey, propDesc) {
console.log('defineProperty')
return Reflect.defineProperty(target, propKey, propDesc)
},
preventExtensions(target) {
console.log('preventExtensions')
return Reflect.preventExtensions(target)
},
getPrototypeOf(target) {// 不同
console.log('getPrototypeOf')
return Reflect.getPrototypeOf(target)
},
isExtensible(target) {
console.log('isExtensible')
return Reflect.isExtensible(target)
},
setPrototypeOf(target, proto) {
console.log('setPrototypeOf')
return Reflect.setPrototypeOf(target, proto)
},
});
// // ====
p.a;
p.plus = '附加属性';
'a' in p;
delete p.plus;
Object.getOwnPropertyNames(p)
Object.getOwnPropertyDescriptor(p, 'a')
Object.defineProperty(p,'c',{
value:'ccc'
});
Object.getPrototypeOf(p)
Object.isExtensible(p)
Object.setPrototypeOf(p,{})
Object.preventExtensions(p); // 放最后, 不然97上面无法设置
console.log('下方是函数的操作')
let Person = function(){
console.log('1111');
}
let proxyFn = new Proxy(Person,{
apply(target, object, args) {
console.log('apply')
return Reflect.apply(target, object, args)
},
construct(target, args) {
console.log('construct')
return Reflect.construct(target, args)
},
});
proxyFn.call({});
// bind没有 因为bind是返回一个新函数,
// 把新函数进行proxy
new proxyFn();
</script>
proxy和defineProperty对比
- proxy还能够检测到更多对象相关的操作,比如构造函数被调用
- 在nodejs x个版本下, 执行多次defineProperty 和proxy,proxy慢了30倍
- 为了继续使用响应式,在vue2.x中额外增加和删除的属性需要使用 Vue.set(对象,添加的key,添加值)
- 【虽然单个API有性能差距,但是到Vue3中,可以利用Proxy带来的便利,在其他方面大幅提升性能】