从源码来看Vue面试题

901 阅读4分钟

1、v-for和v-if同时出现,谁的优先级更高?

  • 显然for的优先级高于if,因为genElement函数中,for比if更早判断

  • 每次执行都会先循环然后判断条件,会导致性能浪费

  • 解决方案:在for外嵌套一层if的判断,或者通过computed提前过滤好渲染列表

2、组件的data选项为什么必须是个函数而Vue的根实例则没有此限制

  • Vue组件会存在多个实例,使用对象定义data会导致其共用一个对象,会造成数据污染

  • 根实例只会被创建一次,因此无须限制

  • 源码上来看,组件实例会比根实例先定义,vm为undefined时,先判断了组件的data情况

3、vue中key的作用和工作原理

  • key的作用是为了高效的更新虚拟dom,原理是在patch过程中,可以快速判断是否是同一个节点,避免频繁更新DOM元素,提升性能
  • 动画过渡时如果不设置key,可能导致动画效果不触发的问题

4、如何理解Vue的diff算法

(源码太多了……暂时没想到有代表性的,具体可以看patch.js)

  • what:diff算法是虚拟DOM技术的必然产物,通过对比新旧的VDOM,更新真实DOM
  • why:每个组件对应一个watcher,通过diff才能找到变化的地方
  • when:组件实例执行更新函数时,对比上一次渲染后的VNode和新的VNode,也叫patch
  • how:深度优先,同层比较。首先假设首尾可能相同做4次同层对比,没有找到则循环遍历查找,可以借助key更高效的查找

5、如何理解Vue组件化

  • what:组件是独立可复用的代码组织单元,可用来构建大型应用(官话)。Vue的组件是基于配置的,平时写的组件本质是组件的配置,通过vue-loader生成其构造函数,基于VueComponent,继承于Vue
  • why:提升开发效率,应用的测试性和复用性
  • how:组件的通信和拓展常用的有props,插槽,注册自定义方法。
  • 其他:组件应该是高内聚低耦合的,Vue组件遵循单项数据流

6、Vue性能优化的方法

1、路由懒加载:

routes: [{ path: '/foo', component: () => import('./foo.vue') }]

2、keep-alive 缓存页面

3、对于渲染时间长的组件,使用v-show复用DOM(对比于v-if)

4、v-for遍历的同时,避免使用v-if

5、对于纯粹的数据展示,使用Object.freeze()阻止响应式

6、使用虚拟滚动列表,每次只渲染少量的数据

7、vue-lazyLoad对图片进行懒加载

8、第三方库按需加载

9、纯展示的无状态组件,可以标记为函数式组件

<template functional>{{ foo }}</template>

10、SSR

7、Vuex的理解

what:集中管理所有组件的状态,并保证状态以某种规则可预测的发生变化

why:解决多组件的状态共享的问题,以全局的单例模式进行管理,代码结构更易维护

should:如果没有大量的全局状态需要维护,其实并不需要用到

how:通过store实例state访问这些状态,通过mutation或者action更改状态

8、Vue-router中路由安全怎么实现

通过路由守卫,设置导航钩子函数,其中判断用户的登录态和权限,来达到保护路由的目的

具体实现:全局前置守卫(beforeEach、beforeResolve、afterEach)、路由独享守卫(beforeEnter)、组件内守卫(beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave)

3种守卫区别:

  • 作用范围
  • 只有组件内守卫可以获取到组件实例
  • 触发顺序不同

9、nextTick的理解

what:Vue.nextTick([callback, context]),在下次DOM更新后执行的延迟回调

why:vue的异步更新策略使得对数据的修改不会立刻更新到视图上,如果想立刻获取到dom状态,则需要调用该方法

how:Vue将开启一个队列(callbacks),缓冲同一事件循环中发生的事件改变,用异步的timerFunc方法(Promise、MutationObserver、setImmediate、setTimeout)去调用,如果同一个watcher被多次触发,则只执行最后一次,从而避免对DOM的重复操作

10、Vue响应式的理解

what:可以检测到数据的变化,并且可以根据这个变化做出响应的机制

why:mvvm架构中需要解决数据层和视图层的连接,通过数据驱动,数据变化,视图更新

how:根据不同的类型做不同的处理,如果是对象则采用Object.defineProperty定义数据拦截,如果是数组,则通过覆盖数组原型的方法,扩展7个可以改变数组长度的方法,使得这些方法做额外的更新通知。可能存在的问题:递归初始化会导致性能损失;新增的属性需要$set特殊处理;对于Set、Map等新数据机构不支持

ToDo:使用Proxy机制代理响应数据,提高初始化性能和减少内存。Vue3中将其抽出为reactivity包,不依赖于Vue