Vue2数据双向绑定的原理(Object.defineProperty)

        首先我们得了解一些MVVM模型, Vue的作者在看到MVVM模型之后, 受到了启发, 开发出了Vue中所特有的模型.

        M: 代表着模型层(Model) 就是data中的数据(一般js对象), V: 代表着视图层(View) 就是DOM元素, VM: 代表着模型层和视图层的链接桥梁 也就是Vue实例.

        

        从这个图中间的两个箭头可以看出来, Vue总共做了两件事:

  • 将data中的数据(一般js对象, 因为data中renturn出来了一个对象), 建设到了DOM元素上.
  • 监听DOM的改变动态的修改data中的数据.

        我们在data中定义的成员都会被挂载到Vue的实例Vm上面, 只要在模板(template)里面进行修改data中的数据, 都会触发视图的改变.

        但是这是有一个前提的, 就是data中所有的成员都需要通过Object.defineProperty进行事件属性拦截, 简答的来说就是他通过Object.defineProperty这个属性将说有成员设置成响应式的.

现在就来介绍一下Object.definProperty:

  • 第一个参数: 需要动态添加成员的对象(target)
  • 第二个参数: 动态添加到目标对象(target)上的属性(property)
  • 第三个参数: 配置项(description), 其中有enumerable、configurable、writable、value、get和set定义的对象.

不要着急哈, 现在来一点一点的了解:

  • 先来对比一下动态添加的属性, 和直接将属性写入对象中有什么区别

        很容易的可以看出两个"age"属性颜色是不同的, 使用Object.defineProperty方法添加的是不可以枚举的.

        枚举的意思就是不能被遍历的, 举个栗子:

直接添加:

 

 

 动态添加:

 

 

  • 再来说一下enumerable、configurable、writable、value这几个成员是如何使用的:
  1. value是动态添加那个属性的属性值
  2. enumerable将它的属性这设置为true的话, 那么动态添加的属性就允许枚举, 默认为false
  3. configurable将它的属性这设置为true的话, 那么动态添加的属性就允许删除, 默认为fasle
  4. writable将它的属性这设置为true的话, 那么动态添加的属性就允许修改, 默认为false

        上述来看, Object.defineProperty条条框框的很多, 很麻烦的样子; 其实不然, 它是一种高级的用法, 可以对属性添加控制.

        不像手动添加属性那样随意, 我们可以对属性更好的控制.

  • 现在就要开始着重的介绍set和get属性了, 数据代理和computed计算属性都是使用的这个底层原理来实现的, 上代码:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
    <div>
      <!-- 发布者 -->
      <input type="text" class="Publisher">

      <!-- 订阅者 -->
      <div class="Subscriber">我是订阅者</div>
    </div>

    <script>
      // 目标对象
      let Target = {}

      let ipt = document.querySelector('.Publisher')
      let div = document.querySelector('.Subscriber')

      Object.defineProperty(Target, 'msg', {
        get() {
          return console.log('有人访问了Target.msg的值')
        },
        set(value) {
          console.log('有人修改了Target.msg的值', value)
          div.innerHTML = value
        }
      })
      
      // 观察者
      ipt.addEventListener('input', (e) => {
        Target.msg = e.target.value
      })
    </script>
</body>
</html>

原理: 

Vue 数据双向绑定原理是通过 数据劫持 + 发布者-订阅者模式 的方式来实现的,首先是通过 ES5 提供的 Object.defineProperty() 方法来劫持(监听)各属性的 getter、setter,并在当监听的属性发生变动时通知订阅者,是否需要更新,若更新就会执行对应的更新函数。

什么是数据劫持

数据劫持比较好理解,通常我们利用Object.defineProperty劫持对象的访问器,在属性值发生变化时我们可以获取变化,从而进行进一步操作。

发布者模式 / 订阅者模式

在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。

这里很明显了,区别就在于,不同于观察者和被观察者,发布者和订阅者是互相不知道对方的存在的,发布者只需要把消息发送到订阅器里面,订阅者只管接受自己需要订阅的内容

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值