Vue学习笔记--Vue双向绑定实现原理

           我们知道Vue可以实现数据双向绑定,AngularVue都是采用的MVVM 模式,意思就是当M(模型层)层数据进行修改时,VM层会监测到变化,并且通知V(视图层)层进行相应的修改,反之修改V层则会通知M层数据进行修改,实现了视图与模型层的相互解耦。其中Angular是采用的脏值检测实现的,Vue是采用的发布-订阅模式+数据劫持 实现的。

          Vue是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的。当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

 

那么先看看Vue对数据的包装吧!使用 Object.getOwnPropertyDescriptor 查看数据属性描述。

    var mydata={
        name:'cc',
        age:'2'
    };
    var app= new Vue({
        el: '#app',
        data: mydata
    });
    console.log(app.name===mydata.name);
    
    console.log(Object.getOwnPropertyDescriptor(app,'name'));
    console.log(Object.getOwnPropertyDescriptor(mydata,'name'));

控制台输出:

Vue学习笔记--Vue双向绑定实现原理_第1张图片

 

诶,可以看到确实Vue对data数据进行了处理,这个动作发生在 Vue生命周期的 beforeCreate  和 created 之间。(注意这里可以看到getter\setter的函数名不一样,这是因为将data对象进行数据劫持之后,要在vue实例对象上可访问,将根级响应式属性代理到了vue实例上

可以试着使用一下Object.defineProperty ,在数据改变的时候得到响应。比如像这样:

var mydata={
    name:'cc',
    age:'2',
    like:{
        dog:'二狗子',
        cat:'小哈'
    }
};

//递归地设置
function DataProcess(data)
{
    if (!data || typeof data !== 'object')
        return;
    Object.keys(data).forEach(function(item){
        definePro(data,item,data[item])
        }
    );
}
function definePro(data,item,val)
{
        DataProcess(val);
        Object.defineProperty(data,item,{
            enumerable: true,
            configurable: true,
            get: function getter () {
                return val;

            },
            set: function setter (newVal) {
                if(val!=newVal)
                {
                    val=newVal;
                    console.log('数据发生了改变!新值为'+newVal);
                }

            }
        });
}

DataProcess(mydata);

mydata.like.dog='eclipse';   //输出:数据发生了改变!新值为eclipse
mydata.like.dog='eclipse';   //这里无输出

 

实现过程:

1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。

Observer是一个数据监听器,其实现核心方法就是前文所说的Object.defineProperty( )。如果要对所有属性都进行监听的话,那么可以通过递归方法遍历所有属性值,并对其进行Object.defineProperty( )处理。

 

 

2.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

compile主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

Compile在vue中这个动作发生在 Vue生命周期的 created 和 mounted之间

 

 

3.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。

Watcher订阅者作为Observer和Compile之间通信的桥梁,主要做的事情是:在自身实例化时往属性订阅器(dep)里面添加自己,自身必须有一个update()方法,待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退




    
    Title
    


{{msg}}

 

具体可以参考下面几篇:

vue的双向绑定原理及实现

剖析Vue原理&实现双向绑定MVVM

 

其他参考:

关于Vue的MVVM

详解vue生命周期

深入响应式原理

 

 

 

 

你可能感兴趣的:(vue)