Vue 响应式原理

1. 这里有一个简单的响应式原理 demo:https://juejin.cn/post/6844903597986037768【转载】

2. 如果说需要我手写出来那还是有一定难度,在这里总结一下:

  首先,Vue 利用 Object.defineProperty 实现了数据劫持;

  属性分为两种,一种是数据属性,另一种是访问器属性。在访问器属性下,可以利用 Object.defineproperty 描述符对象定义四个特性,分别是:

(1)configurable:表示一个属性的特性能否被修改,能否被 delete 删除并重新定义

(2)enumerable:表示一个属性能否被 for...in... 循环返回

(3)get:它是一个 getter 方法,在这里可以进行数据劫持,当我们访问一个属性时,就会进入此方法

(4)set:它是一个 setter 方法,在这里可以进行数据劫持,当我们修改一个属性值,就会进入此方法

接下来,来看一个简单的数据劫持示例:

页面显示部分:

<body>
  <h2></h2>
</body>

JS代码:

<script>
  function Observer(obj) {
    for (let key in obj) {
      defineReactive(obj, key);
    }
  }

  function defineReactive(obj, key) {
    let val = obj[key];
    Object.defineProperty(obj, key, {
      get() {
        console.log("getter executed.");
        return val;
      },
      set(newValue) {
        if (val === newValue) {
          return;
        }
        val = newValue;
        console.log("setter executed");
      }
    })
  }

  function Vue(options) {
    const self = this;
    if (options && typeof options.data === 'function') {
      this._data = options.data.apply(this);
    }
    Observer(this._data);
  }

  const datas = {
    message: "Hello myReactive."
  };

  const vue = new Vue({
    data() {
      return datas;
    }
  });

  let h2 = document.querySelector('h2');
  h2.innerHTML = datas.message;
</script>

   如果改变了 datas 中 message 的值,那么结果如下:

   可以看到 get 和 set 方法都顺利执行,我们在获取数据和改变数据时,都能在这两个方法内部定义我们自己想要的操作。

  其次,Vue 利用了 发布-订阅 模式,实现了对数据的视图更新。

  我们知道,当我们在 Vue 中可能不止一处调用一个 data 中的属性,比如:1. 使用 Mustache 语法在页面上显示属性值 2. 在 computed 中使用属性值 等等...... 那么我们的数据发生变化时,所有这些用到属性的地方,都需要去更新数据,那么它可以利用 Watcher 来对一处数据进行控制。一个属性可能会有多个 Watcher,当数据更新时,需要有一个 Dep 作为发布者,通知所有 Watcher 去进行 update 操作,意味着一个属性会对应一个 Dep.

  也就是说,Object.defineProperty 实现了数据劫持,Dep 【依赖收集器】负责依赖管理,实现了一个发布订阅模式【在 get 方法中收集 Watcher】,当数据有更新时 notify 通知所有 Watcher【在 set 方法调用】,Watcher 是实际上的数据依赖,当数据变化时通过 Watcher 的 update 实现视图更新。

 3. v-model 双向数据绑定:上面所讲的 Vue 响应式原理是单项数据绑定,即属性变化,视图更新,那我们常见的 input 输入使用 v-model,导致属性值变化,是怎么一回事?

  原理就是给 input 添加 oninput 原生 JavaScript 事件,一旦有输入改变属性值,则触发属性的 set 方法,将输入值更新给 data 属性。

posted @ 2021-10-09 20:06  TwinkleG  Views(59)  Comments(0)    收藏  举报