Vue2.X是如何利用Object.defineProperty()实现数据绑定的

上一篇文章写到了Object.defineProperty的应用,这篇文章说一下Vue是如何利用这个办法实现数据绑定的。

首先把Vue中的外围办法defineReactive做一些简化

function defineReactive (obj, key, val, cb) {    var dep = new Dep();    Object.defineProperty(obj, key, {        enumerable: true,        configurable: true,        get: ()=>{            /*....依赖收集等....*/              dep.depend()            return val        },        set:newVal=> {            val = newVal;            /*触发回调*/            dep.notify()        }    })}

Vue通过defineReactive办法实现对须要察看的对象的每个属性进行监控。

dep对象就相当于一个调度核心的作用,如果有数据用到这个属性,它就会主动收集该属性到调度核心,如果某属性产生了扭转,那就会告诉调度核心来更新视图。

再看看dep办法和它的性能。绝对比较简单:1、存储订阅者2、增加订阅者

function Dep () {  // 所有的watcher 放进这里对立治理  this.subs = []}Dep.target = null;// 告诉视图更新dom的 notify的办法Dep.prototype.notify  = function () {  // this.subs 存储 watcher  this.subs.forEach(sub => {    // sub 是某个Watcher 具体调用某个Watcher的update 办法    sub.update()  })}// 增加订阅者的办法Dep.prototype.addSub = function (sub) {  this.subs.push(sub)}

订阅器次要也是了两个办法;1、触发一下属性的获取,顺便把本人加到调度核心去 2、update更新视图

// 具体的订阅器Watcher// 传入一个vue 的示例, 监听的属性, 以及解决的回调函数function Watcher (vm,prop,callback) {  this.vm = vm;  this.$prop = prop;  this.value = this.get();  this.callback = callback; }// 增加watcher 取得属性的get 办法,当有属性拜访/设置 的时候,就产生订阅者 将这个订阅者放进调度核心Watcher.prototype.get = function () {  Dep.target = this;  // 取得属性值  const value = this.vm.$data[this.$prop];  return value}// 增加watcher的更新视图的办法Watcher.prototype.update = function () {  // 当属性值有变动的时候,执行办法,更新试图  const value = this.vm.$data[this.$prop];  this.callback(this.value)}

于是乎

当外界读取数据时会调用watcher,会触发getter把watcher增加到Dep依赖中。(也就是编译过程收集依赖)

当数据产生了变动,会触发setter,从而想Dep中的依赖(watcher)发送告诉。(交互过程,调度核心去告诉订阅器放松更新)。

Watcher 接管到告诉后,会向外界发送告诉,变动告诉到外界可能触发试图更新,也有可能触发用户的某个回调函数等。(订阅器批改对应的值,页面参数随之相应,实现响应)

当然,这才只是单向绑定,双向绑定就是说视图更改数据,这个就比较简单,在编译过程中将标签绑定input办法,批改对应的数据即可。

有来有回,实现了双向绑定。