Proxy实现vue MVVM实践

栏目: JavaScript · 发布时间: 5年前

内容简介:vueconf(2018hangzhou)大会刚刚过去,vue作者尤大大向我们展示了vue3.0的进展,并介绍vue3.0的一些改动,其中最令我期待的就是重写数据监听机制。谈起vue的双向数据绑定,我们首先能想到的就是ES5中我们就针对

vueconf(2018hangzhou)大会刚刚过去,vue作者尤大大向我们展示了vue3.0的进展,并介绍vue3.0的一些改动,其中最令我期待的就是重写数据监听机制。

回顾vue2.x的双向数据绑定

谈起vue的双向数据绑定,我们首先能想到的就是ES5中 Object.defineProperty ,利用重写属性的 getset ,我们可以完成数据劫持监听,使用观察者模式,在数据发生改变的时候,通知订阅者更新状态。

我们就针对 Observer 观察者部分写了一个简易的代码如下:

function Observer (data) {
  this.data = data
  this.walk(data)
}
Observer.prototype = {
  walk: function (data) {
    let me = this
    Object.keys(data).forEach(function (key) {
      me.convert(key, data[key])
    })
  },
  
  convert: function (key, val) {
    this.defineReactive(this.data, key, val)
  },

  defineReactive: function (data, key, val) {
    let dep = new Dep()
    let childObj = observe()

    Object.defineProperty(data, key, {
      enumerable: true,
      configurable: false,
      get: function () {
        if (Dep.target) {
            dep.depend()  // 添加订阅者
        }
        return val
      },
      set: function (newVal) {
        if (newVal === val)  return

        val = newVal
        childObj = observe(newVal)
        dep.notify()  // 通知订阅器
      }
    })
  }
}
function observe (value, vm) {
  if (!value || typeof value !== 'object') {
      return
  }

  return new Observer(value)
}

复制代码

以上代码中我们定义了一个 Observer 构造函数,即观察者。利用 Object.defineProperty 我们将传入对象的所有属性(包含子属性)全部进行数据监听,并在 get 方法中,在订阅器里添加一条订阅。一旦某属性发生改变,通知到订阅器。

Dep订阅器,Compile指令,Watcher订阅者的代码就不再分析,mvvm的总体结构可以由下图看出

Proxy实现vue MVVM实践

整个过程是一个观察者、订阅器、订阅者、指令器四部分的事情,各司其职。

简单介绍Proxy

Proxy是ES6中新增的构造函数,它可以理解为在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤改写。Proxy原意是代理,在这里我们可以理解为“代理”某些操作。

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`proxy get ${key}`)
    return Reflect.get(target, key, receiver)
  },
  set: function (target, key, value, receiver) {
    console.log(`proxy set ${key}`)
    return Reflect.set(target, key, value, receiver)
  }
})
复制代码

上面代码对一个空对象架设了一层拦截,我们可以在Proxy的第二个参数中传入一个 handler 对象,对象中可以定义拦截行为。

getset 中,我们都用到了 ReflectReflect 对象与 Proxy 对象一样,也是ES6位了操作对象而提供的新API。 Reflect 对象的方法与 Proxy 对象的方法一一对应,比如 Proxy 方法拦截 target 对象的属性赋值行为。它采用 Reflect.set 方法将值赋值给对象的属性,确保完成原有的行为,然后再部署额外的功能。

根据以上代码我们写一段测试代码:

obj.text = 'hello world!' 
// proxy set text
var _text = obj.text
// proxy get text
复制代码

Proxy改写观察者

利用以上 Proxy 的一些特性,我们修改代码如下:

function observe (value, vm) {
  if (!value || typeof value !== 'object') {
    return
  }

  let dep = new Dep()
  return new Proxy(value, {
    get: function (target, key, receiver) {
      if (Dep.target) {
        dep.depend()
      }
      return Reflect.get(target, key, receiver)
    },
    set: function (target, key, value, receiver) {
      dep.notify()
      return Reflect.set(target, key, value, receiver)
    }
  })
}
复制代码

我们将传入的对象直接替换为 Proxy 对象,入参 handlergetset 中的添加订阅者和通知订阅器逻辑保持不变。

整个过程没有做其他多余的判断,由于Vue3.0还没有发布,没有实际源码可以借鉴,所以以上只是个人实现的简单版本( 完整代码 )。将整个mvvm运用到html中,以下是运行后的效果(没做gif,凑合看吧):

Proxy实现vue MVVM实践

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

必然

必然

凯文·凯利 (Kevin Kelly) / 周峰、董理、金阳 / 译言·东西文库/电子工业出版社 / 2016-1-1 / 58

《必然》的作者凯文·凯利,被称为“硅谷精神之父”和“世界互联网教父”。前两部《失控》和《科技想要什么》在中国出版后,引起巨大反响。书中凯文·凯利对十二种必然的科技力量加以详细的阐述,并描绘出未来三十年这些趋势如何形成合力指引我们前行的方向。 作者凯文·凯利基于过往从业经历和对未来趋势的敏锐观察对十二个关键词“形成”“知化”“流动”“屏读”“使用”“共享”“过滤”“重混”“互动”“追踪”“提问......一起来看看 《必然》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具