Print

Vue3.0面试题汇总


作者: 文章来源:

本文原地址:https://www.mimiwuqi.com/webqianduan/197236.html

目录文章目录
  1. 介绍一下 Vue 的响应式系统
  2. computed 与 watch 的区别
  3. 介绍一下 Vue 的生命周期
  4. 为什么组件的 data 必须是一个函数
  5. 组件之间是怎么通信的
  6. Vue 事件绑定原理说一下
  7. slot 是什么?有什么作用?原理是什么?
  8. Vue 模板渲染的原理是什么?
  9. template 预编译是什么?
  10. 那 template 和 jsx 的有什么分别?
  11. 说一下什么是 Virtual DOM
  12. 介绍一下 Vue 中的 Diff 算法
  13. key 属性的作用是什么
  14. 说说 Vue2.0 和 Vue3.0 有什么区别
  15. 为什么要新增 Composition API,它能解决什么问题
  16. 都说 Composition API 与 React Hook 很像,说说区别
  17. SSR 有了解吗?原理是什么?

介绍一下 Vue 的响应式系统

Vue 为 MVVM 框架,当数据模型 data 变化时,页面视图会得到响应更新,其原理对datagetter/setter方法进行拦截(Object.defineProperty或者Proxy),利用发布订阅的设计模式,在getter方法中进行订阅,在setter方法中发布通知,让所有订阅者完成响应。

在响应式系统中,Vue 会为数据模型 data 的每一个属性新建一个订阅中心作为发布者,而监听器watch、计算属性computed、视图渲染template/render三个角色同时作为订阅者,对于监听器 watch,会直接订阅观察监听的属性,对于计算属性 computed 和视图渲染 template/render,如果内部执行获取了data的某个属性,就会执行该属性的getter方法,然后自动完成对该属性的订阅,当属性被修改时,就会执行该属性的setter方法,从而完成该属性的发布通知,通知所有订阅者进行更新。

computed 与 watch 的区别

计算属性computed和监听器watch都可以观察属性的变化从而做出响应,不同的是:

计算属性computed更多是作为缓存功能的观察者,它可以将一个或者多个data的属性进行复杂的计算生成一个新的值,提供给渲染函数使用,当依赖的属性变化时,computed不会立即重新计算生成新的值,而是先标记为脏数据,当下次computed被获取时候,才会进行重新计算并返回。

而监听器watch并不具备缓存性,监听器watch提供一个监听函数,当监听的属性发生变化时,会立即执行该函数。

介绍一下 Vue 的生命周期

beforeCreate:是 new Vue()之后触发的第一个钩子,在当前阶段datamethodscomputed以及watch上的数据和方法都不能被访问。

created:在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,在当前阶段无法与 Dom 进行交互,如果非要想,可以通过vm.$nextTick来访问 Dom。

beforeMount:发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated

mounted:在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到 Dom 节点,使用$refs属性对 Dom 进行操作。

beforeUpdate:发生在更新之前,也就是响应式数据发生更新,虚拟 dom 重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。

updated:发生在更新完成之后,当前阶段组件 Dom 已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。

beforeDestroy:发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。

destroyed:发生在实例销毁之后,这个时候只剩下了 dom 空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。

为什么组件的 data 必须是一个函数

一个组件可能在很多地方使用,也就是会创建很多个实例,如果data是一个对象的话,对象是引用类型,一个实例修改了data会影响到其他实例,所以data必须使用函数,为每一个实例创建一个属于自己的data,使其同一个组件的不同实例互不影响。

组件之间是怎么通信的

父组件 -> 子组件:prop

子组件 -> 父组件:$on/$emit

获取组件实例:使用$parent/$children$refs.xxx,获取到实例后直接获取属性数据或调用组件方法

Event Bus:每一个 Vue 实例都是一个Event Bus,都支持$on/$emit,可以为兄弟组件的实例之间 new 一个 Vue 实例,作为Event Bus进行通信。

Vuex:将状态和方法提取到Vuex,完成共享

使用provide/inject

Event Bus:同兄弟组件Event Bus通信

Vuex:将状态和方法提取到 Vuex,完成共享

Vue 事件绑定原理说一下

每一个 Vue 实例都是一个 Event Bus,当子组件被创建的时候,父组件将事件传递给子组件,子组件初始化的时候是有$on方法将事件注册到内部,在需要的时候使用$emit触发函数,而对于原生 native 事件,使用 addEventListener 绑定到真实的 DOM 元素上。

slot 是什么?有什么作用?原理是什么?

slot 又名插槽,是 Vue 的内容分发机制,组件内部的模板引擎使用 slot 元素作为承载分发内容的出口。插槽 slot 是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。

slot 又分三类,默认插槽,具名插槽和作用域插槽。

实现原理:当子组件 vm 实例化时,获取到父组件传入的 slot 标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到 slot 标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

Vue 模板渲染的原理是什么?

vue 中的模板 template 无法被浏览器解析并渲染,因为这不属于浏览器的标准,不是正确的 HTML 语法,所有需要将 template 转化成一个 JavaScript 函数,这样浏览器就可以执行这一个函数并渲染出对应的 HTML 元素,就可以让视图跑起来了,这一个转化的过程,就成为模板编译。

模板编译又分三个阶段,解析 parse,优化 optimize,生成 generate,最终生成可执行函数 render。

template 预编译是什么?

对于 Vue 组件来说,模板编译只会在组件实例化的时候编译一次,生成渲染函数之后在也不会进行编译。因此,编译对组件的 runtime 是一种性能损耗。

而模板编译的目的仅仅是将 template 转化为render function,这个过程,正好可以在项目构建的过程中完成,这样可以让实际组件在 runtime 时直接跳过模板渲染,进而提升性能,这个在项目构建的编译 template 的过程,就是预编译。

那 template 和 jsx 的有什么分别?

对于 runtime 来说,只需要保证组件存在 render 函数即可,而我们有了预编译之后,我们只需要保证构建过程中生成 render 函数就可以。

在 webpack 中,我们使用vue-loader编译.vue 文件,内部依赖的vue-template-compiler模块,在 webpack 构建过程中,将 template 预编译成 render 函数。

与 react 类似,在添加了 jsx 的语法糖解析器babel-plugin-transform-vue-jsx之后,就可以直接手写 render 函数。

所以,template 和 jsx 的都是 render 的一种表现形式,不同的是:

JSX 相对于 template 而言,具有更高的灵活性,在复杂的组件中,更具有优势,而 template 虽然显得有些呆滞。但是 template 在代码结构上更符合视图与逻辑分离的习惯,更简单、更直观、更好维护。

说一下什么是 Virtual DOM

Virtual DOM 是 DOM 节点在 JavaScript 中的一种抽象数据结构,之所以需要虚拟 DOM,是因为浏览器中操作 DOM 的代价比较昂贵,频繁操作 DOM 会产生性能问题。虚拟 DOM 的作用是在每一次响应式数据发生变化引起页面重渲染时,Vue 对比更新前后的虚拟 DOM,匹配找出尽可能少的需要更新的真实 DOM,从而达到提升性能的目的。

介绍一下 Vue 中的 Diff 算法

在新老虚拟 DOM 对比时

在 diff 中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从O(n^3)降低值O(n),也就是说,只有当新旧 children 都为多个子节点时才需要用核心的 Diff 算法进行同层级比较。

key 属性的作用是什么

在对节点进行diff的过程中,判断是否为相同节点的一个很重要的条件是key是否相等,如果是相同节点,则会尽可能的复用原有的 DOM 节点。所以 key 属性是提供给框架在 diff 的时候使用的,而非开发者。

说说 Vue2.0 和 Vue3.0 有什么区别

  1. 重构响应式系统,使用Proxy替换Object.defineProperty,使用Proxy优势:
  1. 新增Composition API,更好的逻辑复用和代码组织
  2. 重构 Virtual DOM
  1. 代码结构调整,更便于Tree shaking,使得体积更小
  2. 使用Typescript替换Flow

为什么要新增 Composition API,它能解决什么问题

Vue2.0 中,随着功能的增加,组件变得越来越复杂,越来越难维护,而难以维护的根本原因是 Vue 的 API 设计迫使开发者使用watchcomputedmethods选项组织代码,而不是实际的业务逻辑。

另外 Vue2.0 缺少一种较为简洁的低成本的机制来完成逻辑复用,虽然可以minxis完成逻辑复用,但是当 mixin 变多的时候,会使得难以找到对应的datacomputed或者method来源于哪个 mixin,使得类型推断难以进行。

所以 Composition API 的出现,主要是也是为了解决 Option API 带来的问题,第一个是代码组织问题,Compostion API 可以让开发者根据业务逻辑组织自己的代码,让代码具备更好的可读性和可扩展性,也就是说当下一个开发者接触这一段不是他自己写的代码时,他可以更好的利用代码的组织反推出实际的业务逻辑,或者根据业务逻辑更好的理解代码。

第二个是实现代码的逻辑提取与复用,当然 mixin 也可以实现逻辑提取与复用,但是像前面所说的,多个 mixin 作用在同一个组件时,很难看出 property 是来源于哪个 mixin,来源不清楚,另外,多个 mixin 的property存在变量命名冲突的风险。而 Composition API 刚好解决了这两个问题。

都说 Composition API 与 React Hook 很像,说说区别

React Hook的实现角度看,React Hook 是根据 useState 调用的顺序来确定下一次重渲染时的state是来源于哪个 useState,所以出现了以下限制

而 Composition API 是基于 Vue 的响应式系统实现的,与 React Hook 的相比

虽然 Compositon API 看起来比 React Hook 好用,但是其设计思想也是借鉴React Hook的。

SSR 有了解吗?原理是什么?

在客户端请求服务器的时候,服务器到数据库中获取到相关的数据,并且在服务器内部将 Vue 组件渲染成 HTML,并且将数据、HTML 一并返回给客户端,这个在服务器将数据和组件转化为 HTML 的过程,叫做服务端渲染 SSR。

而当客户端拿到服务器渲染的 HTML 和数据之后,由于数据已经有了,客户端不需要再一次请求数据,而只需要将数据同步到组件或者 Vuex 内部即可。除了数据意外,HTML 也结构已经有了,客户端在渲染组件的时候,也只需要将 HTML 的 DOM 节点映射到 Virtual DOM 即可,不需要重新创建 DOM 节点,这个将数据和 HTML 同步的过程,又叫做客户端激活。

使用 SSR 的好处:

更多 建站教程 请访问 https://www.mimiwuqi.com/webqianduan/