Vue3面试知识点

Vue3 面试知识点

1. Vue3 的响应式

关键词

Proxy, Refelct

特点

  • 众所周知Vue2的响应式是通过Object.defineProperty()来劫持各个属性的 get 和 set,当数据变化时发布消息给订阅者,触发监听回调,但是其实这个 API 存在很多问题
  • Vue3中为了解决这些问题,使用了ProxyReflect来代替他
    • 支持监听对象和数组的变化
    • 对象嵌套属性时只代理第一层,运行时才递归代理深层,性能更好
    • 能拦截对象 13 种方法,新增数据结构都支持
  • 提供了俩个 API:ref, reactive

什么是 Proxy

Proxy用与创建一个目标对象的代理,在对目标对象的操作之前提供了拦截,可以对外界的操作进行过滤和改写。这样我们可以不直接操作对象本身,而是通过操作代理对象来间接操作对象

defineProperty 和 Proxy 的区别

  • defineProperty是 ES5 的方法,Proxy是 ES6 的
  • defineProperty是劫持对象的某个属性,Proxy是代理整个对象
  • defineProperty监听对象/数组时,需要迭代对象的每个属性
  • defineProperty不能监听道对象的新增属性,Proxy可以
  • defineProperty不支持Map, Set等数据结构
  • defineProperty只支持 get 和 st,而Proxy支持 13 种方法
  • Proxy兼容性差,且无法通过pollyfill解决,所以Vue3不支持 IE

为什么需要 Reflect

不会 Reflect,怎么玩转 Proxy –Reflect 篇

大多数情况我们很少使用到 Reflect,他使用最多的就是配合 Proxy 使用。他的方法和 Proxy 的方法数量相同,并且方法名一模一样,而且他返回的值也正是 Proxy 需要的值。

其实就是相当于不用我们自己手写时间 get/set 等,直接 return Reflect.get(…arguments)就可以了

  • 使用Reflect可以修正Proxy的 this 问题(这点有待研究)
  • Proxy的一些方法要求返回 boolean 来表示操作是否成功,这也和Reflect对应
  • 以前的许多借口都定义在Object上,历史原因越来越杂,所以直接干脆都挪到Reflect上,目前是 13 种,之后可能新增

对数组的处理

Vue2对数组的监听做了特殊处理,Vue3也需要做处理,原因是:

  • push, pop等方法操作数组时会隐式访问和修改数组的length,所以我们需要这时停止依赖追踪
  • includes, indexOf, lastIndexOf这些查找时,可能是使用代理对象进行查找,也有可能使用原始值去查找,使用需要重写,先去响应式对象中找,没找到再去原始值内找

源码地址: packages/reactivity/src/baseHandlers.ts#L48

惰性响应式

  • Vue2对一个深层前端套的对象做响应式,需要递归遍历他,每一层都变成了响应式
  • 但是在Vue3中为了减少性能消耗,只有在 getter 中用到的内部属性才去递归响应式

源码地址: packages/reactivity/src/baseHandlers.ts#L155

也就是因为这个,所以对象其实只代理了第一层,只有当 get 时拿到的返回值是 Object 的时候,才会用 reactive 进行深度代理。

但是也带来了解构丢失响应式的问题

  • Vue3响应式数据使用ES6解构出来的是一个引用对象类型时,它还是响应式的(因为返回的是响应式数据)。但是解构出的是基本数据类型时,响应式会丢失。

Set、Map 做的处理

因为 Proxy 无法直接拦截题目,他们的方法必须在自身调用,所以 Vue3 封装了 toRaw()返回原对象

参考文章