# 浅讨论下 vue2 和 vue3 的区别

# vue2 是如何实现响应式的?

  • 实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器 Observer,用来监听所有属性。如果属性发生变化了,就需要告诉订阅者 Watcher (Watcher 是一个封装了渲染视图逻辑的类,用于派发更新的),结合Vnode经过patch()中的diff算法看是否需要更新(dep.notify() 通知 收集的 Watcher 重新渲染)。因为订阅者 Watcher 是有很多个,所以每一个属性都有自己的一个消息订阅器Dep来专门收集这些订阅者(即以依赖的watcher),然后在监听器 Observer 和订阅者Watcher 之间进行统一管理
  • Dep 相当于把 Observe 监听到的信号做一个收集(collect dependencies),然后通过 dep.notify()再通知到对应 Watcher ,从而进行视图更新。

# 在数据劫持方面从 vue2 的 Object.defineProperty()升级为 Proxy,这样做有什么好处?

  • 解决了在 vue2 中 set 方法监听不到数组的改变,无需重写 array 原型上的方法,因为数组也是对象,能够被监听到
  • 给对象新增加一个属性时,不需要再手动去监听这个新增属性(使用 vm.$set 才能保证新增的属性也是响应式的)
  • vue2 实现了一个definedReactive,内部是用Object.defineProperty对每一个属性进行监听,需要遍历来对所有属性监听,只能监控到最外层的对象,深度监听一个对象时需要递归,Proxy 代理的是整个对象,而不是对象的某个特定属性,不需要我们通过遍历来逐个进行数据绑定
  • 在使用 Object.defineProperty()给对象添加一个属性之后,我们对对象属性的读写操作仍然在对象本身。在 Proxy 中,如果想要读写操作生效,我们就要对 Proxy 的实例对象 proxyObj 进行操作。
  • defineProperty实际上是对象的基本操作,而这些对象内部的基本操作,通过Proxy暴露给开发者,这些13种拦截操作提供给开发者更多的操作空间(可以定义陷阱函数)proxyMdn (opens new window)
//Object.defineProperty
// 实现一个响应式函数
function defineProperty(obj, key, val) {
  //如果某对象的属性也是一个对象,递归进入该对象,进行监听
  if (typeof val === "object") {
    observer(val);
  }
  Object.defineProperty(obj, key, {
    get() {
      console.log(访问了key属性);
      return val;
    },
    set(newVal) {
      // 如果newVal是一个对象,递归进入该对象进行监听
      if (typeof val === "object") {
        observer(key);
      }
      console.log(key属性被修改为newVal了);
      val = newVal;
    },
  });
}
// 实现一个遍历函数Observer
function Observer(obj) {
  //如果传入的不是一个对象,return
  if (typeof obj !== "object" || obj === null) return;
  Object.keys(obj).forEach((key) => {
    defineProperty(obj, key, obj[key]);
  });
}

//Observer:观察者对象,对对象或数组进行响应式处理的地方
//defineReactive:拦截对象上每一个key的get与set函数的地方
//observe:响应式处理的入口
//Proxy
//定义handler对象
let hander = {
  get(obj, key) {
    // 如果对象里有这个属性,就返回属性值,如果没有,就返回false
    return key in obj ? obj[key] : false;
  },
  set(obj, key, val) {
    obj[key] = val;
    return true;
  },
};

# Vue3.0 优点

  • 将 Vue 内部的绝大部分 api 对外暴露,使 Vue 具备开发大型项目的能力,例如 compile 编译 api 等
  • webpack 的 treeshaking(tree shaking 是 DCE 的一种方式,它可以在打包时忽略没有用到的代码。)支持度友好
  • 使用 Proxy 进行响应式变量定义,性能提高,对 typescript 支持更加友好
  • 受 ReactHook 启发,可在 Vue2.0 中单独使用 composition-api 插件,或者直接用它开发插件
  • Vue 3 的 Template 支持多个根标签,Vue 2 不支持
  • Vue 3 的 v-if 优先于 v-for 生效,Vue2反之
Last Updated: 8/24/2023, 9:41:33 AM