使用Proxy实现双向绑定

前言

技术从来不会受限于语言,受限你的,永远只是思想。(博主发现了一个有意思的机器学习库,TensorFlow的js版本,有兴趣的同学可以看一下https://www.tensorflow.org/api_docs)

=> 这里以Proxy为例来进行编码,当然,我们需要事先了解一下Proxy的使用方法.

Proxy就像一个代理器,当有人对目标对象进行处理(set、has、get 等等操作)的时候它会首先经过它,这时我们可以使用代码进行处理,此时Proxy相当于一个中介或者叫代理人,它经常被用于代理模式中,可以做字段验证、缓存代理、访问控制等等。

1.Object.defineProperty

众所周知,vue使用了Object.defineProperty来做数据劫持,它是利用劫持对象的访问器,在属性值发生变化时我们可以获取变化,从而进行进一步操作。

// 例子:对对象属性a的拦截
const obj = { a: 1 }
Object.defineProperty(obj, 'a', {
  get: function() {
    console.log('get val')
  },
  set: function(newVal) {
    console.log('set val:' + newVal)
  }
})

2.与Object.defineProperty相比,Proxy的优势

  1. 数组作为特殊的对象,但Object.defineProperty无法监听数组变化。

  2. Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历,如果属性值也是对象那么需要深度遍历,显然能劫持一个完整的对象是更好的选择。

  3. Proxy 有多达 13 种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的。

  4. Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改

  5. Proxy作为新标准将受到浏览器厂商重点持续的性能优化

/*
 * Vue主要有两个方法
 * $proxy: 把输入对象属性代理到vue实例上
 * $watch: 监听对象的变化
 */
class Vue {
  constructor(data) {
    this.$data = data
    Object.keys(data).forEach(key => this.$proxy(key))
  }
  $watch(key, cb) {
    new Watcher(this, key, cb)
  }
  $proxy(key) {
    Reflect.defineProperty(this, key, {
      configurable: true,
      enumerable: true,
      get: () => this.$data[key],
      set: val => {
        this._data[key] = val
      }
    })
  }
}

/*
 * Watcher
 * 监听数据变化,并通知变化
 */
class Watcher {
  constructor(vm, key, callback) {
    this.vm = vm // vue实例
    this.callback = callback // 回调:返回更新
    this.key = key // 被订阅的数据
    this.val = this.get() // 维护更新之前的数据
    vm.$data = this.createProxy(vm.$data) // 为数据做代理
  }

  update(newVal) {
    this.callback(newVal)
  }
  get() {
    const val = this.vm.$data[this.key]
    return val
  }
  createProxy(data) {
    let _this = this
    let handler = {
      get(target, property) {
        return Reflect.get(target, property)
      },
      set(target, property, value) {
        let res = null
        if (target[property] != value) {
          const isOk = Reflect.set(target, property, value)
          if (_this.key === property) {
            // 同一层级
            res = value
          } else {
            res = _this.get()
            console.log(res)
          }
          _this.callback(res)
          return isOk
        }
      }
    }

    return toDeepProxy(data, handler)

    function toDeepProxy(object, handler) {
      if (!isPureObject(object)) addSubProxy(object, handler)
      return new Proxy(object, handler)

      function addSubProxy(object, handler) {
        for (let prop in object) {
          if (typeof object[prop] == 'object') {
            if (!isPureObject(object[prop])) addSubProxy(object[prop], handler)
            object[prop] = new Proxy(object[prop], handler)
          }
        }
        object = new Proxy(object, handler)
      }

      function isPureObject(object) {
        if (typeof object !== 'object') {
          return false
        } else {
          for (let prop in object) {
            if (typeof object[prop] == 'object') {
              return false
            }
          }
        }
        return true
      }
    }
  }
}

双向绑定的完整例子已放在 codepen

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程介绍本套课程,大喵将带着大家手把手,编辑每一行代码,使用原生Javascipt及ES6的一些新特性,仿照目前国内非常流行的Vue框架的源码,开发构建一个属于你们自己的MVVM框架。让大家能够很清晰的学习及掌握,模板编译,数据绑定,响应式,文档碎片,观察者模式,发布订阅模式等等,这些Vue的核心知识点,都是怎么回事,它们之间有哪些关联,是如何进行双向数据绑定的等等。在使用vue2.x的核心Object.defineProperty构建完成框架后,大喵也会使用Vue3.0引入的数据劫持的Proxy新特性,来改造我们的MVVM框架,提升我们的框架性能。最终,大喵会手把手带着大家,从0开始配置webpack.config.js配置文件以及引入babel-loader,配置.babelrc文件,转换我们JS文件中的的ES6语法,最终压缩输出我们的MVVM框架库文件。课程目录01 手把手搭建MVVM框架 课程介绍、02 文件结构及基础类创建、03 入口类DamiaoMvvm的实现、04 模板编译、05 元素节点解析编译、06 v-model 数据绑定逻辑梳理、07 v-model 数据绑定实现、08 模板文本编译逻辑梳理、09 模板文本渲染绑定、10 观察者Wather逻辑梳理、11 Wather 逻辑实现、12 Object.defineProperty()、13 defineProperty 小案例、14 observer数据劫持梳理、15 defineProperty数据劫持实现、16 发布订阅类实现、17 Proxy 介绍与概述、18 使用Proxy改造MVVM框架、19 使用Proxy实现响应式、20 webpack 打包配置、21 babel 配置及文件输出、22 Mvvm Proxy 框架打包、23 Mvvm 框架搭建课程总结MVVM框架介绍MVVM是 Model-View-ViewModel 的缩写。mvvm是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。在MVVM架构模式下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值