尤雨溪在今年国庆节5号预发布了vue3,98%是ts写的,这说明来年ts应该会处于一个很重要的位置,要学ts咯哈哈哈。那么都快要使用3了,vue2.x和vue3的数据响应式原理有什么差异?我单独分析一个点。
首先看看原理图
vue2.x用的核心函数是Object.defineProperty,defineProperty核心并不是为对象做数据绑定的,而是给对象的属性做一些配置,只不过里面的set和get实现了响应式。defineProperty的缺陷是只能监听一个属性,所以要想监听一个对象,vue2的内部做了一个for in 处理。先写一个vue2.x版本的简单demo
function Vue(){
//选项写死,便于演示
this.$data = {
a:1
};
this.el = document.getElementById('app');
this._html = '';
this.observe(this.$data);
this.render();
}
Vue.prototype.observe= function(obj){
var value;
var that = this;
for(var key in obj){
value = obj[key];
if(typeof value === 'object'){
this.observe(value);
}else{
Object.defineProperty(this.$data,key,{
get:function(){
return value
},
set:function(newValue){
value = newValue;
self.render();
}
})
}
}
}
Vue.prototype.render = function(){
// 这里实际复杂的多节,解析模板(template),虚拟dom 转真实dom
this._html = this.$data.a;
this.el.innerHTML = this._html;
}
// 只要this.$data改变就会触发试图更新
var $vm = new Vue();
setTimeout(()=>{
$vm.$data.a = 1000; //模拟数据更改
},2000)
而vue3用proxy写,proxy可以监听整个对象。省去for in提升效率,并且可以监听数组,不用再去单独的对数组做特异性操作(此点下面会详细说明白)。
function Vue(){
this.$data = {
a:1
};
this.el = document.getElementById('app');
this._html = '';
this.observe(this.$data);
this.render();
}
Vue.prototype.observe= function(obj){
var value;
var that = this;
// 用proxy就不需要for in了,即监听的颗粒度减小了,拿到的信息更多了。
this.$data = new Proxy(obj,{
get:function(target,key,reveive){
return target[key];// 不需要中间变量了
},
set: function (target, key, newValue,reveive){
target[key] = newValue;
}
})
}
Vue.prototype.render = function(){
// 这里实际复杂的多节,解析模板(template),虚拟dom 转真实dom
this._html = this.$data.a;
this.el.innerHTML = this._html;
}
// 只要this.$data改变就会触发试图更新
var $vm = new Vue();
setTimeout(() => {
$vm.$data.a = 1000; //模拟数据更改
}, 2000)
以前我们要是更改数组某个下标的值直接arr[1]=xx是不生效的,这是因为defineProperty根本就监听不到,所以试图更新就无法更改。那么为什么push和和pop以及全部替换就能生效呢,因为官方提供了7个数组的变异方法,这个问题也可以参考以前我粗俗的理解,以前真的不知道原理,乱写了一篇文章:https://blog.csdn.net/ChasenZh/article/details/78045330 ,(这篇文章是写的很迷糊的,但是人会成长嘛哈哈哈哈哈)。
但是具体参见(https://cn.vuejs.org/v2/guide/list.html#%E6%95%B0%E7%BB%84%E6%9B%B4%E6%96%B0%E6%A3%80%E6%B5%8B)
有7个方法,分别是:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
何为变异方法,就是这些数组方法的原有功能保持不变,我们在这些方法的基础上增加了一些功能,也就是所谓的装饰者模式。怎么变异的呢?代码如下:
var arrPro = Array.prototype;
var arrOb = Object.create(arrPro);
var arr = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort','reverse'];
//arr里的方法,既能保持原有的方法,又能触发更新。
//装饰者模式
arr.forEach(function(method,index){
arrOb[method] = function(){
var ret = arrPro[method].apply(this, arguments);
//render() 这里触发试图更新。
// 用console.log()替代一下
console.log('触发试图更新')
return ret;
}
});
var test = [];
test.__proto__ = arrOb;
test.push(2)
然而,vue3之后就不需要这么干了,说明以后arr[1]=xx 这样也能触发试图了,因为proxy可以监听到数组的变化,所以从侧面也能说明vue3确实优化了很多东西。