vue2 中defineProperty
封装实现对特定数据的监控
function vue() {
this.data = {a: 1};
this.ele = document.getElementById('root');
this.virtualDom = '';
this.observer(this.data);
}
vue.prototype.observer = function (target) {
var value = {};
var self = this;
for(var m in target) {
if(typeOf target[m] ==='object') {
this.observer(target[m]);
} else{
Object.defineProperty(this.data, m, {
get: function() {
// 还需要 dep.append()确认属性和依赖的组件的关系
return value;
},
set: function(newValue) {
value = newValue;
// 实际上,需要做 dep.notify()定向局部更新组件视图
self.render();
return value;
},
})
}
}
}
// 简单render
vue.prototype.render = function (){
this.virtualDom = 'i am' + this.data.a;
this.ele.innerHTML = this.virtualDom;
}
然而在对数组类型数据监控时
arr.unShift(4); // 出栈入栈触发setget多次, 获取值再平移下标赋值
get key: 2 value: 3
get key: 1 value: 2
set key: 2 value: 2
get key: 0 value: 1
set key: 1 value: 1
set key: 0 value: 4
observe()
arr[4] // 无法触发get
由于之前监听的下标改变了,没有监听新增的下标
可以通过在数组下标变化时重新监听该数组达到解决以上问题,vue2中的源码observe对数组和对象的情况单独处理,做了Arr.protoype(push 、 pop 、 shift 、 unshift 、 splice 、 sort 、 reverse)封装, 在下标变化时重新observe, 这样一来代码和内存开销加大;
对数组的原型方法重写
var needOperate = [ 'shift' , 'unshift', 'splice', ' sort',' reverse'];
var newProto = Array.prototype;
var newArray = Object.create(newProto);
needOperate.forEach(item => {
newArray[item] = function () {
var reset = needOperate[item].apply(this, aguments);
observe(); // 重新更新组件下标的监听
dep.notify;
}
})
Vue3的proxy
Object.defineProperty只能劫持对象的属性,而Proxy是直接代理对象返回新的代理对象,不需要遍历递归去完成属性的代理。
Object.defineProperty对新增属性需要手动进行Observe
vue3中不是直接调用,而是先通过一个方法去执行
function vue() {
this.data = {a: 1};
this.ele = document.getElementById('root');
this.virtualDom = '';
this.observer(this.data);
}
vue.prototype.observer = function (target) {
var self = this;
this.data = new proxy(target, {
get: function(target, key) {
return target[key]
},
set: function(target, key) {
Reflect.set(target, key, value)
},
})
}
// 简单render
vue.prototype.render = function (){
this.virtualDom = 'i am' + this.data.a;
this.ele.innerHTML = this.virtualDom;
}