vue2响应式原理

77 阅读3分钟

数据属性描述符

var obj = {
        name: "xxx",
        age: 18,
};


 Object.defineProperty(obj, "name", {
        configurable: false, //告诉js引擎,obj.name不能被删除
        enumerable: false, //告诉js引擎,obj.name属性不能被枚举(for in/Object.keys())
        writable: false, //告诉js引擎,obj对象的name属性不写入(只读属性readonly)
        value: "xxx", //告诉js引擎,返回这个value
      });

其中,第三个参数有一些配置项。

  • configurable告诉js引擎,obj.name能否被删除

  • enumerable告诉js引擎,obj.name属性能否被枚举(for in/Object.keys())

  • writable 告诉js引擎,obj对象的name属性能否被写入(只读属性readonly)

  • value 告诉js引擎,返回这个value

存储属性描述符

var obj = { name: "xxx" };
      var _name = "";
      Object.defineProperty(obj, "name", {
        configurable: true,
        enumerable: false,
        set: function (value) {
          _name = value;
          console.log("set", value);
        },
        get: function () {
          console.log("get");
          return _name;
        },
      });

当我们读取obj.name的时候,会触发get() 当我们修改obj.name的时候,会触发set()

发布订阅模式

  • 1.vue响应原理: vue.js采用数据劫持结合发布-订阅者模式,通过Object.defineProperty()来劫持data中各个属性的setter、getter,在数据变动时,发布消息给订阅者,触发响应的监听回调。

  • 2、发布-订阅者模式的作用:

处理一对多的场景,应用于不同情况下的不同函数调用

优点:低耦合性,易于代码维护;

缺点:若订阅的消息未发生,需消耗一定的时间和内存。

其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知

image.png

vue2

vue2的响应式原理主要使用的是Object.defineProperty( ) ,里面需要传入三个参数,分别是:
【响应源数据的对象,源数据中的需要读写的属性,相对应的对象方法(包含了get和set方法)】

    <script>
      // 存储属性描述符
      // vue2响应式原理
      var obj = { name: "xxx" };
      var _name = "";
      Object.defineProperty(obj, "name", {
        configurable: true,
        set: function (value) {
          console.log("调用了set方法,修改了name属性");
          obj.name = value;
        },
        get: function () {
          console.log("调用了get方法,获取了name属性");
          return obj.name;
        },
      });

      //调用Object.defineProperty中的get方法获取数据
      console.log(obj.name);

      //调用Object.defineProperty中的set方法修改数据
      obj.name = "张三";
    </script>

在上面的示例中,我们利用了JS对象中的defineProperty()方法对对象person进行了数据劫持。

vue响应式也叫作数据双向绑定,大致原理阐述:

  • 首先我们需要通过Object.defineProperty()方法把数据(data)设置为getter和setter的访问形式,这样我们就可以在数据被修改时在setter方法设置监视修改页面信息,也就是说每当数据被修改,就会触发对应的set方法,然后我们可以在set方法中去调用操作dom的方法。

  • 此外,如果页面有input用v-model绑定数据,我们需要在这种绑定了data的input元素上添加监听,添加input事件监听,每当input事件被触发时,就修改对应的data。

vue实现数据响应式,是通过数据劫持侦测数据变化,发布订阅模式进行依赖收集与视图更新,换句话说是Observe,Watcher以及Compile三者相互配合,

  • Observe实现数据劫持,递归给对象属性,绑定setter和getter函数,属性改变时,通知订阅者
  • Compile解析模板,把模板中变量换成数据,绑定更新函数,添加订阅者,收到通知就执行更新函数
  • Watcher作为Observe和Compile中间的桥梁,订阅Observe属性变化的消息,触发Compile更新函数

VUE2.0响应式数据存在的缺陷

  • 从上面看下来,你已经知道了,在vue2.0中,响应式原理使用了- Object.definedProprety实现了数据响应式。但是Object.definedProperty还存在了一定的缺陷。

  • 无法监听到对象属性的动态添加和删除 无法监听到数组下标和length长度的变化

所以vue2.0中提供给了我们 $get $set $delete这些方法用来弥补不足

总结vue2响应式原理

是利用defineproperty来实现具体来说是对data里的属性都设置了getter 和setter,

  • getter收集依赖就是收集每个标签和每个数据属性的对应关系,
  • 当data对象中属性修改赋值的时候就会触发对应的setter函数拦截进行视图更新。

image.png