Vue响应式指的是:组件的data发生变化,立刻触发视图的更新 。

原理:
Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,在getter中收集依赖,在setter中触发依赖。
即把用到该数据的地方收集起来,然后等属性发生变化时,把之前收集好的依赖循环触发一遍。

vue2通过Object.defineProperty来劫持数据的setter,getter。
获取属性值会触发getter方法, 设置属性值会触发setter方法, 在setter方法中调用修改dom的方法来实现视图的更新 。

var obj = {};
Object.defineProperty(obj, 'val', {
    get: function () {
        console.log('获取属性值')
        track(obj, "val");//依赖收集
    },
    set: function (newVal) { 
        console.log('设置属性值:最新的值是'+newVal);
        trigger(obj, "val");//触发更新
    }
});

Object.defineProperty的缺点

  1. 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历,如果属性值也是对象那么需要深度遍历,数据很大时,大量的递归会导致调用栈溢出 。
  2. 不能监听对象的新增属性和删除属性。
  3. 无法正确的监听数组的方法,无法监控到数组下标的变化,当直接通过数组的下标给数组设置值时arr[4]=2,不能实时响应。

Vue3.0 是通过Proxy实现的数据双向绑定,Proxy是ES6中新增的一个特性,实现的过程是在目标对象之前设置了一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

Proxy 只需要做一层代理就可以监听同级结构下的所有属性变化,当然对于深层结构,递归还是需要进行的。此外 Proxy支持代理数组的变化。

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

用法:
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
const p = newProxy(target, handler)
target: 是用Proxy包装的被代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

function reactive(obj) {
  returnnewProxy(obj, {
    get(target, key) {
      //搜集依赖
      track(target, key);
      return target[key]
    },
    set(target, key, value) {
      target[key] = value
      trigger(target, key);//触发更新
    }
  })
}