Vue相关

17 阅读4分钟

所有问题答案均为精简版,详情版后续补充链接

Vue2与Vue3有什么异同:

  • 数据劫持优化:

    • Vue2 中的Object.defineProperty,因为需要预先知道要拦截的key是什么,所以并不能检测对象属性的添加和删除,对于一个较深层级的对象来说,不管是否会访问到深层级的属性,都会进行深度监听,一次性计算量大
    • Vue3使用的proxy实现。对于深层级对象,仍然需要递归实现,但是它是在proxy的getter操作中赋予响应式。意味着只有访问到这个层级的属性才会建立响应,而不是像2一样直接给整个对象都加上响应。
  • 渲染优化(渲染器):

    从双端Diff算法升级为快速Diff算法

  • 编译优化(编译器)

    • 通过数据劫持和依赖收集,Vue2数据更新并触发重新渲染的粒度是组件级的。

      由于 Vue 使用了模板和组件的组合方式,每个组件都有自己独立的数据对象、依赖收集和渲染上下文。这意味着数据变化只会触发当前组件内部的重新渲染,不会影响其他组件,因此数据更新和重新渲染的粒度是组件级的。

      但如果组件中有静态节点,即以后都不会发生改变,但是Diff算法还是会重新比较这些静态节点,尽管我们已经知道这些比较毫无意义。

    • Vue3在编译阶段对静态模板进行了分析,编译生成了BlockTree,它会指导Diff算法的执行跳过静态节点。

  • 组合式APi(写法)

    • 无需额外考虑this指向,调用者只需要关系函数的返回值

    • 代码简洁,快速开发

      • 函数式编程大量使用函数,减少了代码的重复,降低服用成本
      • 在选项式中通过mixin可以使用代码复用,但是使用它可能会导致`数据来源不明确和命名冲突
    • 方便的代码管理,方便调试

    函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合。易于"并发编程"

    • 打包过程中可以更好的利用 tree shaking 过滤无用代码
  • 源码体积优化

    • 移除了部分API,例如filter等
    • 引入tree-shaking减小打包体积。
  • 框架、源码层面优化

    Vue2的源码统一放在src下,Vue3则是放在package下。内部文件都是根据功能划分,但是Vue3的功能划分力度更细致,每个项目之间没有影响,有着自己的API,类型定义和单元测试。

    Vue3用的是typeScript。对于框架、组件库typeScript很有必要,因为有利于IDE自动补全,并且有更清晰的架构

    例如:若只想获得Vue提供的响应式能力,对于2来说,则需要引入整个Vue.js.但是对于3来说,可以仅引用Vue下的reactivity响应库。

$nextTick是如何实现的

Vue用异步队列的方式来控制DOM更新和nextTick回调先后执行。microtask因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕。因为浏览器和移动端兼容问题,Vue不得不做了microtaskmacrotask的兼容(降级)方案。

  1. 主要思路是通过event loop最后的UI render,只要让nextTick里的代码放在UI render步骤后面执行,就能访问到更新后的DOM了。
  2. 每一次事件循环都包含一个microtask队列,在循环结束后会依次执行队列中的microtask并移除,然后再开始下一次事件循环。
  3. 不能使用微任务时,只能用宏任务了(降级策略):setImmediate(只支持IE和nodejs)、MessageChannel(回调也是microtask,但也是个新API,面临兼容性的尴尬)、setTimeout(执行的最小时间间隔是约4ms)
  4. 最终降级原则保留为Promise=>MutationObserver=>setImmediate=>MessageChannel=>setTimeout

Pinia与Vuex的区别

  1. 无需要创建自定义的复杂包装器来支持 TypeScript,一切都可标注类型,API 的设计方式是尽可能地利用 TS 类型推理;
  2. 弃用了mutation;
  3. Pinia没有modules,如果想使用多个store,直接定义多个store传入不同的id即可,故也无需嵌套合并至一个store中;
  4. Pinia是可以直接修改状态的,并且调试工具能够记录到每一次state的变化,而vuex直接修改不能够记录每一次state的变化记录,需要在mutation中修改,影响我们的调试。当vuex开启严格模式的时候,直接修改state会抛出错误;
  5. Pinia可以使用$reset将状态重置为初始值;
  6. Pinia支持了storeToRefs可以使用ES6解构;
  7. Vuex中commit和dispatch会有过多的魔法字符串注入,而pinia只需要导入函数并调用它们,然后享受自动补全的乐趣就好。

Proxy 与 Object.defineProperty 的区别及优劣势

Proxy 的优势如下:

  1. Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性;
  2. 数组新增删除修改时,Proxy可以监听到;
  3. Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
  4. 如果对象内部要全部递归代理,则Proxy可以只在调用时递归,而Object.defineProperty需要在一开始就全部递归,Proxy性能优于Object.defineProperty;
  5. 对象上定义新属性时,Proxy可以监听到;

Object.defineProperty 的优势如下:

  1. 兼容性好,支持 IE9及以上,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。

【keep-alive】的实现及常考点

贴一个自己的文章Vue-keepAlive的实现与考点

vue组件data为什么是函数

当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。
如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!
通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

随时更新中。。。敬请期待