Vue双向数据绑定:Object.defineProperty和Proxy

本文探讨了Vue的双向数据绑定机制,包括数据劫持和订阅者模式。通过分析Object.defineProperty实现双向数据绑定的过程,进一步使用Proxy进行优化。文中详细解释了Object.defineProperty的局限性和Vue如何通过递归遍历data对象实现数据监控。接着介绍了Proxy的优势,它能劫持整个对象并返回新对象,提高操作性和性能。文章通过示例代码展示了两种方法的实现,并指出使用Proxy时的一个小错误及解决方案。
摘要由CSDN通过智能技术生成

 

前言:我们从以前的操作DOM元素到现在的操作数据,从以前的MVC模式到现在的MVVM模式,以及现在深入人心的组件化开发,这个转折我觉得真的是太机智了。

现在我们平常开发主要用到的技术里,可以看到React和小程序是单向数据流,Vue和Angular是双向数据绑定,Angular用的是脏检测,Vue则是数据劫持和订阅者模式,今天我们来聊聊vue的双向数据绑定。

 

双向数据绑定无非就是,视图 => 数据,数据 => 视图的更新过程

借张图:

以下的方案中的实现思路:

  1. 定义一个Vue的构造函数并初始化这个函数
  2. 实现数据层的更新:数据劫持,定义一个 obverse 函数重写data的set和get
  3. 实现视图层的更新:订阅者模式,定义个 Watcher 函数实现对DOM的更新
  4. 将数据和视图层进行绑定,解析指令v-bind、v-model、v-click
  5. 创建Vue实例

好了下面我们要开始干正事了

这两天突然看到一个公众号文章,里面介绍了 Object.defineProperty 如何实现vue的双向数据绑定,虽然这类文章看过好多遍,但还是忍不住好奇心撮进去看了一眼(估计是因为养了猫的原因吧)

这一看不得了,还有这么简洁的实现方式

好像再涂涂改改一下我是不是能用 Proxy 来实现一遍???

好吧,说动手就动手,这一动手就是一整天,先修改了下它的代码能少多少少多少,顺便带上自己的注释,方便一会用 Proxy 方法来改造。

Object.defineProperty 实现方式的原文:面试题:你能写一个 Vue 的双向数据绑定吗?

下图就是我们实现双向数据后的页面,很简洁的三个元素

默认值:

修改了值后:

以下是我涂涂改改后用 Object.defineProperty 方式实现的代码,因为我的注释很详细,所以就不说怎么实现的了,如果你之前没有了解过这方面的知识,那么你可以先看看原文再过来看这段代码和注释

因为修改过和原文有些不同,但是思路大概一样

看完后你会发现 Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue里,是通过递归以及遍历data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历

<!DOCTYPE html>
<html>

<head>
  <title>myVue</title>
  <style>
    #app{
    text-align: center;
  }
</style>
</head>

<body>
  <div id="app">
    <form>
      <input type="text" v-model="number" />
      <button type="button" v-click="increment">增加</button>
    </form>
    <h3 v-bind="number"></h3>
  </div>
</body>
<script>

  // 定义一个myVue构造函数
  function myVue(option) {
    this._init(option)
  }

  myVue.prototype._init = function (options) { // 传了一个配置对象
    this.$options = options // options 为上面使用时传入的结构体,包括el,data,methods
    this.$el = document.querySelector(options.el) // el是 #app, this.$el是id为app的Element元素
    this.$data = options.data // this.$data = {number: 0}
    this.$methods = options.methods // this.$methods = {increment: function(){}}


    // _binding保存着model与view的映射关系,也就是我们前面定义的Watcher的实例。当model改变时,我们会触发其中的指令类更新,保证view也能实时更新
    this._binding = {}

    this._obsever(this.$data)
    this._compile(this.$el)
  }

  // 数据劫持:更新数据
  myVue.prototype._obsever = function (obj) {
    let _this = this
    Object.keys(obj).forEach((key) => { // 遍历obj对象
      if (obj.hasOwnProperty(ke
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值