vue2.x和vue3的数据响应式原理

尤雨溪在今年国庆节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确实优化了很多东西。

猜你喜欢

转载自blog.csdn.net/ChasenZh/article/details/102760184