vue必会⾯试题+答案
vue必会⾯试题+答案
vue视频教程系列:
腾讯Vue实战问卷⽹站视频教程
完整教程⽬录:
最新 Vue+Spring 旅游项⽬
完整教程⽬录:
Vue3.0(正式版) + TS 仿知乎专栏企业级项⽬
完整教程⽬录:
Vue3.0+TS打造企业级组件库前端中⾼级开发者必修课
完整教程⽬录:
基于VantUI的Vue移动端电商项⽬实战
完整教程⽬录:
Vue为什么没有类似于React中shouldComponentUpdate的⽣命周期?
考点: Vue的变化侦测原理
前置知识: 依赖收集、虚拟DOM、响应式系统
根本原因是Vue与React的变化侦测⽅式有所不同
React是pull的⽅式侦测变化,当React知道发⽣变化后,会使⽤Virtual Dom Diff进⾏差异检测,但是很多组件实际上是肯定不会发⽣变化的,这个时候需要⽤shouldComponentUpdate进⾏⼿动操作来减少diff,从⽽提⾼程序整体的性能.
Vue是pull+push的⽅式侦测变化的,在⼀开始就知道那个组件发⽣了变化,因此在push的阶段并不需要⼿动控制diff,⽽组件内部采⽤的diff ⽅式实际上是可以引⼊类似于shouldComponentUpdate相关⽣命周期的,但是通常合理⼤⼩的组件不会有过量的diff,⼿动优化的价值有限,因此⽬前Vue并没有考虑引⼊shouldComponentUpdate这种⼿动优化的⽣命周期.
Vue中的key到底有什么⽤?
key是为Vue中的vnode标记的唯⼀id,通过这个key,我们的diff操作可以更准确、更快速
diff算法的过程中,先会进⾏新旧节点的⾸尾交叉对⽐,当⽆法匹配的时候会⽤新节点的key与旧节点进⾏⽐对,然后超出差异.
diff程可以概括为:oldCh和newCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互⽐较,⼀共有4种⽐较⽅式。如果4种⽐较都没匹配,如果设置了key,就会⽤key进⾏⽐较,在⽐较的过程中,变量会往中间靠,⼀旦StartIdx>EndIdx表明oldCh和newCh⾄少有⼀个已经遍历完了,就会结束⽐较,这四种⽐较⽅式就是⾸、尾、旧尾新头、旧头新尾.
准确: 如果不加key,那么vue会选择复⽤节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产⽣⼀系列的bug.
快速: key的唯⼀性可以被Map数据结构充分利⽤,相⽐于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1).
vue和react的区别
=> 相同点:
1. 数据驱动页⾯,提供响应式的试图组件
2. 都有virtual DOM,组件化的开发,通过props参数进⾏⽗⼦之间组件传递数据,都实现了webComponents规范
3. 数据流动单向,都⽀持服务器的渲染SSR
4. 都有⽀持native的⽅法,react有React native, vue有wexx
=> 不同点:
1.数据绑定:Vue实现了双向的数据绑定,react数据流动是单向的
2.数据渲染:⼤规模的数据渲染,react更快
3.使⽤场景:React配合Redux架构适合⼤规模多⼈协作复杂项⽬,Vue适合⼩快的项⽬
4.开发风格:react推荐做法jsx + inline style把html和css都写在js了
vue是采⽤webpack + vue-loader单⽂件组件格式,html, js, css同⼀个⽂件
Vue模版编译原理知道吗,能简单说⼀下吗?
简单说,Vue的编译过程就是将template转化为render函数的过程。会经历以下阶段:
⽣成AST树
优化
codegen
⾸先解析模版,⽣成AST语法树(⼀种⽤JavaScript对象的形式来描述整个模板)。 使⽤⼤量的正则表达式对模板进⾏解析,遇到标签、⽂本的时候都会执⾏对应的钩⼦进⾏相关处理。
Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有⼀些数据⾸次渲染后就不会再变化,对应的DOM也不会变化。那么优化过程就是深度遍历AST树,按照相关条件对树节点进⾏标记。这些被标记的节点(静态节点)我们就可以跳过对它们的⽐对,对运⾏时的模板起到很⼤的优化作⽤。
编译的最后⼀步是将优化后的AST树转换为可执⾏的代码。
Vue.js的template编译
简⽽⾔之,就是先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点),详细步骤如下:
⾸先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形
式),compile是createCompiler的返回值,createCompiler是⽤以创建编译器的。另外compile还负责合并option。
然后,AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是
VNode,VNode是Vue的虚拟DOM节点,⾥⾯有(标签名、⼦节点、⽂本等等)
了解nextTick吗?
异步⽅法,异步渲染最后⼀步,与JS事件循环联系紧密。主要使⽤了宏任务微任务(tTimeout、promi那些),定义了⼀个异步⽅法,多次调⽤nextTick会将⽅法存⼊队列,通过异步⽅法清空当前队列。
说说Vue的⽣命周期吧
什么时候被调⽤?
beforeCreate :实例初始化之后,数据观测之前调⽤
created:实例创建万之后调⽤。实例完成:数据观测、属性和⽅法的运算、watch/event 事件回调。⽆$el .
beforeMount:在挂载之前调⽤,相关render 函数⾸次被调⽤
mounted:了被新创建的vm.$el替换,并挂载到实例上去之后调⽤改钩⼦。
beforeUpdate:数据更新前调⽤,发⽣在虚拟DOM重新渲染和打补丁,在这之后会调⽤改钩⼦。
updated:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调⽤改钩⼦。
beforeDestroy:实例销毁前调⽤,实例仍然可⽤。
destroyed:实例销毁之后调⽤,调⽤后,Vue实例指⽰的所有东西都会解绑,所有事件监听器和所有⼦实例都会被移除
每个⽣命周期内部可以做什么?
created:实例已经创建完成,因为他是最早触发的,所以可以进⾏⼀些数据、资源的请求。
mounted:实例已经挂载完成,可以进⾏⼀些DOM操作。
beforeUpdate:可以在这个钩⼦中进⼀步的更改状态,不会触发重渲染。
updated:可以执⾏依赖于DOM的操作,但是要避免更改状态,可能会导致更新⽆线循环。
destroyed:可以执⾏⼀些优化操作,清空计时器,解除绑定事件。
ajax放在哪个⽣命周期?:⼀般放在mounted 中,保证逻辑统⼀性,因为⽣命周期是同步执⾏的,ajax 是异步执⾏的。单数服务端渲
染ssr 同⼀放在created 中,因为服务端渲染不⽀持mounted ⽅法。 什么时候使⽤beforeDestroy?:当前页⾯使⽤$on ,需要解绑事件。清楚定时器。解除事件绑定,scroll moumove 。
写过⾃定义指令吗原理是什么
指令本质上是装饰器,是 vue 对 HTML 元素的扩展,给 HTML 元素增加⾃定义功能。vue 编译 DOM 时,会找到指令对象,执⾏指令的相关⽅法。
⾃定义指令有五个⽣命周期(也叫钩⼦函数),分别是 bind、inrted、update、componentUpdated、unbind
1. bind:只调⽤⼀次,指令第⼀次绑定到元素时调⽤。在这⾥可以进⾏⼀次性的初始化设置。
2. inrted:被绑定元素插⼊⽗节点时调⽤ (仅保证⽗节点存在,但不⼀定已被插⼊⽂档中)。
3. update:被绑定于元素所在的模板更新时调⽤,⽽⽆论绑定值是否变化。通过⽐较更新前后的绑定值,可以忽略不必要的模板更新。
4. componentUpdated:被绑定元素所在模板完成⼀次更新周期时调⽤。
5. unbind:只调⽤⼀次,指令与元素解绑时调⽤。
v-show 与 v-if 有什么区别?
v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和⼦组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第⼀次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进⾏切换。
所以,v-if 适⽤于在运⾏时很少改变条件,不需要频繁切换条件的场景;v-show 则适⽤于需要⾮常频繁切换条件的场景。
Vue 组件间通信有哪⼏种⽅式?
Vue 组件间通信是⾯试常考的知识点之⼀,这题有点类似于开放题,你回答出越多⽅法当然越加分,表明你对 Vue 掌握的越熟练。Vue 组件间通信只要指以下 3 类通信:⽗⼦组件通信、隔代组件通信、兄弟组件通信,下⾯我们分别介绍每种通信⽅式且会说明此种⽅法可适⽤于哪类组件间通信。
(1)props / $emit 适⽤ ⽗⼦组件通信
这种⽅法是 Vue 组件的基础,相信⼤部分同学⽿闻能详,所以此处就不举例展开介绍。
(2)ref 与 $parent / $children 适⽤ ⽗⼦组件通信
ref:如果在普通的 DOM 元素上使⽤,引⽤指向的就是 DOM 元素;如果⽤在⼦组件上,引⽤就指向组件实例
$parent / $children:访问⽗ / ⼦实例
(3)EventBus ($emit / $on) 适⽤于 ⽗⼦、隔代、兄弟组件通信
这种⽅法通过⼀个空的 Vue 实例作为中央事件总线(事件中⼼),⽤它来触发事件和监听事件,从⽽实现任何组件间的通信,包括⽗⼦、隔代、兄弟组件。
(4)$attrs/$listeners 适⽤于 隔代组件通信
$attrs:包含了⽗作⽤域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当⼀个组件没有声明任何 prop 时,这⾥会包含所有⽗作⽤域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind="$attrs" 传⼊内部组件。通常配合 inheritAttrs 选项⼀起使⽤。
$listeners:包含了⽗作⽤域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传⼊内部组件
(5)provide / inject 适⽤于 隔代组件通信
祖先组件中通过 provider 来提供变量,然后在⼦孙组件中通过 inject 来注⼊变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使⽤场景,主要是⼦组件获取上级组件的状态,跨级组件间建⽴了⼀种主动提供与依赖注⼊的关系。
(6)Vuex 适⽤于 ⽗⼦、隔代、兄弟组件通信
Vuex 是⼀个专为 Vue.js 应⽤程序开发的状态管理模式。每⼀个 Vuex 应⽤的核⼼就是 store(仓库)。“store” 基本上就是⼀个容器,它包含着你的应⽤中⼤部分的状态 ( state )。
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发⽣变化,那么相应的组件也会相应地得到⾼效更新。
改变 store 中的状态的唯⼀途径就是显式地提交 (commit) mutation。这样使得我们可以⽅便地跟踪每⼀个状态的变化。
Vue 怎么⽤ vm.$t() 解决对象新增属性不能响应的问题?
受现代 JavaScript 的限制 ,Vue ⽆法检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执⾏ getter/tter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。但是 Vue 提供了 Vue.t (object, propertyName, value) / vm.$t (object, propertyName, value) 来实现为对象添加响应式属性,那框架本⾝是如何实现的呢?
我们查看对应的 Vue 源码:vue/src/core/instance/index.js
export function t(target: Array<any>| Object, key: any, val: any): any {
// target 为数组
if(Array.isArray(target)&&isValidArrayIndex(key)){
// 修改数组的长度, 避免索引>数组长度导致splcie()执⾏有误
target.length = Math.max(target.length, key)
// 利⽤数组的splice变异⽅法触发响应式
target.splice(key,1, val)
return val
}
// key 已经存在,直接修改属性值
if(key in target &&!(key in Object.prototype)){
target[key]= val
return val
}
const ob =(target: any).__ob__
// target 本⾝就不是响应式数据, 直接赋值
if(!ob){
target[key]= val
return val
}
// 对属性进⾏响应式处理
defineReactive(ob.value, key, val)
ify()
return val
}
我们阅读以上源码可知,vm.$t 的实现原理是:
如果⽬标是数组,直接使⽤数组的 splice ⽅法触发相应式;
如果⽬标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进⾏响应式处理,则是通过调⽤ defineReactive ⽅法进⾏响应式处理( defineReactive ⽅法就是 Vue 在初始化对象时,给对象属性采⽤ Object.defineProperty 动态添加 getter 和tter 的功能所调⽤的⽅法)
虚拟 DOM 的优缺点?
优点:
保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产⽣的操作,它的⼀些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是⽐起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM ⾄少可以保证在你不需要⼿动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
⽆需⼿动操作 DOM: 我们不再需要⼿动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的⽅式更新视图,极⼤提⾼我们的开发效率;
跨平台: 虚拟 DOM 本质上是 JavaScript 对象,⽽ DOM 与平台强相关,相⽐之下虚拟 DOM 可以进⾏更⽅便地跨平台操作,例如服务器渲染、weex 开发等等。
缺点:
⽆法进⾏极致优化: 虽然虚拟 DOM + 合理的优化,⾜以应对绝⼤部分应⽤的性能需求,但在⼀些性能要求极⾼的应⽤中虚拟 DOM ⽆法进⾏针对性的极致优化。
虚拟 DOM 实现原理?
虚拟 DOM 的实现原理主要包括以下 3 部分:
⽤ JavaScript 对象模拟真实 DOM 树,对真实 DOM 进⾏抽象;
diff 算法 — ⽐较两棵虚拟 DOM 树的差异;
pach 算法 — 将两个虚拟 DOM 对象的差异应⽤到真正的 DOM 树。
如果对以上 3 个部分还不是很了解的同学,可以查看本⽂作者写的另⼀篇详解虚拟 DOM 的⽂章《》
你有对 Vue 项⽬进⾏哪些优化?
如果没有对 Vue 项⽬没有进⾏过优化总结的同学,可以参考本⽂作者的另⼀篇⽂章,⽂章主要介绍从 3 个⼤⽅⾯,22 个⼩⽅⾯详细讲解如何进⾏ Vue 项⽬的优化。
(1)代码层⾯的优化
v-if 和 v-show 区分使⽤场景
computed 和 watch 区分使⽤场景
v-for 遍历必须为 item 添加 key,且避免同时使⽤ v-if
长列表性能优化
事件的销毁
图⽚资源懒加载
路由懒加载
第三⽅插件的按需引⼊
优化⽆限列表性能
服务端渲染 SSR or 预渲染
(2)Webpack 层⾯的优化