写点什么

vue 面试题八股文简答大全 让你更加轻松的回答面试官的 vue 面试题

作者:肥晨
  • 2023-03-30
    江苏
  • 本文字数:4367 字

    阅读完需:约 14 分钟


你对 vue 框架的理解?

Vue.js 是一个流行的 JavaScript 框架,它使得构建复杂的交互式应用程序变得更容易。Vue.js 基于 MVVM 模式设计,采用了响应式数据绑定和组件化的架构。在 Vue.js 中,数据绑定是非常重要的概念,它通过使用观察者模式来追踪数据变化并自动更新 DOM。


Vue.js 源码是一个庞大而复杂的项目,但通过掌握其核心概念,我们可以更好地理解其工作原理。在本文中,我们讨论了 Vue.js 的响应式数据绑定、虚拟 DOM、模板编译、组件、生命周期钩子、事件处理和指令等关键知识点。了解这些知识点可以让我们更好地编写 Vue.js 应用程序,并深入了解 Vue.js 的工作原理

计算属性和侦听器

Vue.js 提供了计算属性和侦听器来处理数据的变化。计算属性是用于计算和缓存的属性,而侦听器则允许你监听数据的变化并执行特定的操作。这两个概念都是基于 Vue.js 的响应式数据绑定实现的。


计算属性的实现是通过使用 Object.defineProperty()方法来定义 getter 和 setter 方法。当计算属性依赖的数据发生变化时,计算属性会重新计算,这样可以避免重复计算。侦听器则是通过使用 Watcher 对象来实现的。

Vue.js 中的虚拟 DOM

Virtual DOM 是 Vue.js 的一个核心概念,它是一个“轻量级”的 DOM 副本,作为内存中的 JavaScript 对象存在。每次数据发生变化时,Vue.js 会计算需要更新的最小 DOM 子树,然后只更新这些部分。这种方法比直接操作真实 DOM 要快得多。


在 Vue.js 中,虚拟 DOM 由 VNode 类来表示。VNode 类有一些属性:tag、data、children 等。VNode 实例通常通过 createElement()方法创建,该方法返回一个 VNode 实例。

模板编译

Vue.js 使用模板来描述应用程序的界面,而模板编译是将模板转换为渲染函数的过程。在 Vue.js 中,模板编译是由 template 编译器来处理的。它将模板解析为 AST(抽象语法树),然后将 AST 转换为渲染函数。


Vue.js 的模板编译器是独立的,可以在浏览器中运行。在开发环境中,模板编译器会被自动加载,并且 Vue.js 还提供了一个单独的运行时构建,不包含模板编译器。这意味着你需要在构建工具中对模板进行预编译,或者使用手动渲染函数。

组件

组件是 Vue.js 的另一个核心概念,它允许你构建可重用和可组合的 UI 组件。在 Vue.js 中,每个组件都是一个 Vue 实例,并且可以包含其他组件。组件可以接收属性(props)和发射事件,以便与其他组件进行通信。


Vue.js 中的组件是通过 Vue.extend()方法来创建的。该方法将基本 Vue 类与组件定义合并,并返回一个新的构造函数。然后可以在应用程序中使用自定义标记(例如<my-component>)来创建组件实例。

生命周期钩子

Vue.js 的生命周期钩子是一系列函数,它们定义了 Vue 实例在不同阶段执行的操作。这些阶段包括:创建、挂载、更新和销毁。生命周期钩子可以在 Vue 实例的选项对象中定义。


在 Vue.js 中有 7 个生命周期钩子:


created: 在 Vue 实例创建后调用,但在模板渲染之前。


mounted: 在 Vue 实例挂载到 DOM 上后调用。


updated: 在 Vue 实例数据被更新后调用,但在 DOM 重新渲染之前。


destroyed: 在 Vue 实例销毁之前调用。


beforeCreate: 在 Vue 实例创建之前调用。


beforeMount: 在 Vue 实例挂载到 DOM 之前调用。


beforeUpdate: 在 Vue 实例数据更新之前调用,但在 DOM 重新渲染之前。

Vue.js 中的事件处理

在 Vue.js 中,你可以使用 v-on 指令来绑定 DOM 事件。例如,你可以使用 v-on:click 来监听点击事件。事件处理程序可以是内联函数,也可以是 Vue.js 组件的方法。事件处理程序可以接收一个事件对象作为参数。


在 Vue.js 的事件处理中,事件是经过封装的。在组件内部使用on 来监听事件。这样可以避免直接操作 dom 元素,使代码更加清晰和易于维护。

Vue.js 中的指令

Vue.js 中的指令是特殊的 HTML 属性,它们可以用于指定某些特殊行为。例如,v-if 和 v-for 指令用于条件渲染和循环渲染。指令可以接收表达式作为参数,并可以在表达式变化时进行更新。


Vue.js 提供了一些内置指令,包括 v-model、v-bind、v-on 等。我们可以自定义指令来扩展 Vue.js 的功能。自定义指令需要使用 Vue.directive()方法来定义。

简述 MVVM

MVVM 是 Model-View-ViewModel 缩写,也就是把 MVC 中的 Controller 演变成 ViewModel。Model 层代表数据模型,View 代表 UI 组件,ViewModel 是 View 和 Model 层的桥梁,数据会绑定到 viewModel 层并自动将数据渲染到页面中,视图变化的时候会通知 viewModel 层更新数据。

v-for 中 key 的作用

  1. key 的作用主要是为了更高效的对比虚拟 DOM 中每个节点是否是相同节点;

  2. Vue 在 patch 过程中判断两个节点是否是相同节点,key 是一个必要条件,渲染一组列表时,key 往往是唯一标识,所以如果不定义 key 的话,Vue 只能认为比较的两个节点是同一个,哪怕它们实际上不是,这导致了频繁更新元素,使得整个 patch 过程比较低效,影响性能;

  3. 从源码中可以知道,Vue 判断两个节点是否相同时主要判断两者的 key 和元素类型等,因此如果不设置 key,它的值就是 undefined,则可能永 远认为这是两个相同的节点,只能去做更新操作,这造成了大量的 dom 更新操作,明显是不可取的。

vue 组件的通信方式

父子组件通信父->子 props,子->父 emit 获取父子组件实例 parent、parent、children Ref 获取实例的方式调用组件的属性或者方法 Provide、inject 官方不推荐使用,但是写组件库时很常用


兄弟组件通信 Event Bus 实现跨组件通信 Vue.prototype.$bus = new Vue() Vuex


跨级组件通信listeners Provide、inject

路由传参

  1. 使用 router-link 进行路由导航,传递参数

  2. 直接调用 $router.push 实现携带参数的跳转

  3. 通过路由属性中的 name 来确定匹配的路由,通过 params 来传递参数

  4. 使用 path 来匹配路由,然后通过 query 来传递参数,这种情况下 query 传递的参数会显示在 url

路由的两种模式 hash 与 history

对于 Vue 这类渐进式前端开发框架,为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-router 存在的意义。前端路由的核心,就在于改变视图的同时不会向后端发出请求。1、hash ——即地址栏 URL 中的 #符号,它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。


2、history ——利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器的历史记录站,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改是,虽然改变了当前的 URL,但你浏览器不会立即向后端发送请求。history 模式,会出现 404 的情况,需要后台配置。

双向绑定实现原理

当一个 Vue 实例创建时,Vue 会遍历 data 选项的属性,用 Object.defineProperty 将它们转为 getter/setter 并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

v-model 的实现以及它的实现原理吗?

  1. vue 中双向绑定是一个指令 v-model,可以绑定一个动态值到视图,同时视图中变化能改变该值。v-model 是语法糖,默认情况下相于:value 和 @input。

  2. 使用 v-model 可以减少大量繁琐的事件处理代码,提高开发效率,代码可读性也更好

  3. 通常在表单项上使用 v-model

  4. 原生的表单项可以直接使用 v-model,自定义组件上如果要使用它需要在组件内绑定 value 并处理输入事件

  5. 我做过测试,输出包含 v-model 模板的组件渲染函数,发现它会被转换为 value 属性的绑定以及一个事件监听,事件回调函数中会做相应变量更新操作,这说明神奇魔法实际上是 vue 的编译器完成的。

new Vue 后整个的流程

initProxy:作用域代理,拦截组件内访问其它组件的数据。initLifecycle:建立父子组件关系,在当前组件实例上添加一些属性和生命周期标识。如[Math Processing Error]parent,parent,refs,$children,_isMounted 等。initEvents:对父组件传入的事件添加监听,事件是谁创建谁监听,子组件创建事件子组件监听 initRender:声明[Math Processing Error]slots 和 slots 和 createElement()等。initInjections:注入数据,初始化 inject,一般用于组件更深层次之间的通信。initState:重要)数据响应式:初始化状态。很多选项初始化的汇总:data,methods,props,computed 和 watch。initProvide:提供数据注入。思考:为什么先注入再提供呢??


1、首先来自祖辈的数据要和当前实例的 data,等判重,相结合,所以注入数据的 initInjections 一定要在 InitState 的上面。


  1. 从上面注入进来的东西在当前组件中转了一下又提供给后代了,所以注入数据也一定要在上面。

keep-alive 的实现

keep-alive 是 Vue 的内置组件,实现组件缓存。当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁。keep-alive 是系统自带的一个组件,用来缓存组件,避免多次加载相同的组件,减少性能消耗,提高用户体验。例如我们可以在列表页进入详情页使用。如果在列表页点击的都是相同的 ,详情页就不用请求多次了,直接缓存起来就行了,如果点击的不同,则需要重新请求数据

vuex、vue-router 实现原理

vuex 是一个专门为 vue.js 应用程序开发的状态管理库。 核心概念:


state(单一状态树) getter/Mutation 显示提交更改 stateAction 类似 Mutation,提交 Mutation,可以包含任意异步操作。module(当应用变得庞大复杂,拆分 store 为具体的 module 模块)

你怎么理解 Vue 中的 diff 算法?

在 js 中,渲染真实 DOM 的开销是非常大的, 比如我们修改了某个数据,如果直接渲染到真实 DOM, 会引起整个 dom 树的重绘和重排。那么有没有可能实现只更新我们修改的那一小块 dom 而不要更新整个 dom 呢?此时我们就需要先根据真实 dom 生成虚拟 dom, 当虚拟 dom 某个节点的数据改变后会生成有一个新的 Vnode, 然后新的 Vnode 和旧的 Vnode 作比较,发现有不一样的地方就直接修改在真实 DOM 上,然后使旧的 Vnode 的值为新的 Vnode。


diff 的过程就是调用 patch 函数,比较新旧节点,一边比较一边给真实的 DOM 打补丁。在采取 diff 算法比较新旧节点的时候,比较只会在同层级进行。 在 patch 方法中,首先进行树级别的比较 new Vnode 不存在就删除 old Vnodeold Vnode 不存在就增加新的 Vnode 都存在就执行 diff 更新 当确定需要执行 diff 算法时,比较两个 Vnode,包括三种类型操作:属性更新,文本更新,子节点更新 新老节点均有子节点,则对子节点进行 diff 操作,调用 updatechidren 如果老节点没有子节点而新节点有子节点,先清空老节点的文本内容,然后为其新增子节点 如果新节点没有子节点,而老节点有子节点的时候,则移除该节点的所有子节点 老新老节点都没有子节点的时候,进行文本的替换


updateChildren 将 Vnode 的子节点 Vch 和 oldVnode 的子节点 oldCh 提取出来。 oldCh 和 vCh 各有两个头尾的变量 StartIdx 和 EndIdx,它们的 2 个变量相互比较,一共有 4 种比较方式。如果 4 种比较都没匹配,如果设置了 key,就会用 key 进行比较,在比较的过程中,变量会往中间靠,一旦 StartIdx>EndIdx 表明 oldCh 和 vCh 至少有一个已经遍历完了,就会结束比较。

发布于: 刚刚阅读数: 3
用户头像

肥晨

关注

还未添加个人签名 2021-04-15 加入

平台:InfoQ、阿里云、腾讯云、CSDN、掘金、博客园等平台创作者 领域:前端 公众号:农民工前端

评论

发布
暂无评论
vue面试题八股文简答大全 让你更加轻松的回答面试官的vue面试题_Vue_肥晨_InfoQ写作社区