vue的data数据双向绑定原理及实现

Object.defineProperty()

该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
例:

//在console.log(book.name)同时,直接给书加一个书号
var Book = {};
var name = '';
Object.defineProperty(Book,'name',{
    set:function(value) {
        name = value;
        console.log('你取了一个书名叫:'+value);
    },
    get:function() {
        console.log('get方法被监听到');
        return '<'+name+'>';
    }
});
Book.name = '人性的弱点';  //你取了一个书名叫:人性的弱点
console.log(Book.name); //<人性的弱点>

此处代码转自

利用这个特性,vue遍历传入每个实例的data对象
源码

//遍历传入实例的data对象的属性,将其设置为Vue对象的访问器属性
 function observe(obj,vm){
     Object.keys(obj).forEach(function(key){
         defineReactive(vm,key,obj[key]);
     });
 }
 //设置为访问器属性,并在其getter和setter函数中,使用订阅发布模式。互相监听。
 function defineReactive(obj,key,val){
     //这里用到了观察者模式,它定义了一种一对多的关系,让多个观察者监听一个主题对象,这个主题对象的状态发生改变时会通知所有观察者对象,观察者对象就可以更新自己的状态。
     //实例化一个主题对象,对象中有空的观察者列表
     var dep = new Dep();
     //将data的每一个属性都设置为Vue对象的访问器属性,属性名和data中相同
     //所以每次修改Vue.data的时候,都会调用下边的get和set方法。然后会监听v-model的input事件,当改变了input的值,就相应的改变Vue.data的数据,然后触发这里的set方法
     Object.defineProperty(obj,key,{
         get: function(){
             //Dep.target指针指向watcher,增加订阅者watcher到主体对象Dep
             if(Dep.target){
                 dep.addSub(Dep.target);
             }
             return val;
         },
         set: function(newVal){
             if(newVal === val){
                 return
             }
             val = newVal;
             //console.log(val);
             //给订阅者列表中的watchers发出通知
             dep.notify();
         }
     });
 }
 
 //主题对象Dep构造函数
 function Dep(){
     this.subs = [];
 }
 //Dep有两个方法,增加订阅者  和  发布消息
 Dep.prototype = {
     addSub: function(sub){
         this.subs.push(sub);
     },
     notify: function(){
         this.subs.forEach(function(sub){
             sub.update();
         });
     }
 }

通过订阅发布消息的方式,监听每个数据的改变

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容