当前位置: 首页 > Web前端 > vue.js

vue必遇面试题+答案

时间:2023-03-31 21:32:18 vue.js

vue必遇面试题+答面试题视频讲解(高效学习):为什么Vue在学习Vue时没有类似于React中shouldComponentUpdate的生命周期?考点:Vue的变更检测原理前置知识:依赖收集、虚拟DOM、响应式系统根本原因是Vue和React的变更检测方式不同。React以拉取方式检测变化。当React知道发生变化时,会使用VirtualDomDiff进行差异检测,但很多组件肯定不会发生变化。这时候就需要使用shouldComponentUpdate进行手动操作来减少diffs,从而提高程序的整体性能。vue使用pull+push来检测变化,如果要测量变化,从一开始就知道组件发生了变化,所以不需要在push阶段手动控制diff,组件内部使用的diff方法就可以其实引入了类似shouldComponentUpdate的生命周期,但是通常合理的大小组件不会有过大的diff,手动优化的价值有限。所以Vue目前不考虑引入shouldComponentUpdate这种手动优化的生命周期。Vue中的键有什么用?key是在Vue中为vnode标记的唯一id。通过这把钥匙,我们的diff操作可以更准确、更快速。在diff算法的过程中,会先进行新旧节点的第一次和最后一次交叉比较。当没有匹配时,将使用新的。该节点的key与旧节点进行比较,然后超出差值。diff过程可以概括为:oldCh和newCh各有两个头尾变量StartIdx和EndIdx,它们的两个变量相互比较。一共有4种比较方式。如果四个比较都不匹配,如果设置了key,则使用key进行比较。在比较过程中,变量会向中间倾斜。一旦StartIdx>EndIdx表示至少遍历了oldCh和newCh中的一个,就结束比较,这四种比较方式分别是head,tail,oldtailnewhead,oldheadnewtail。准确:如果没有添加key,那么Vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态如果被保留,就会产生一系列的bug。快速:键的唯一性可以被Map数据结构充分利用。相对于遍历搜索的时间复杂度O(n),Map的时间复杂度仅为O(1).vue与react的区别=>相同点:1.数据驱动页面,提供响应式视图组件2.两者都有虚拟DOM,组件化开发,父子组件之间通过props参数传递数据,实现webComponentsSpecification3.单向数据流,均支持服务端渲染SSR4。两者都支持native方法,react有Reactnative,vue有wexx=>区别:1.数据绑定:Vue实现双向数据绑定,React数据流是单向2.数据渲染:大规模数据渲染,反应更快3.使用场景:React和Redux架构适合大型多人协作和复杂项目,Vue适合小而快的项目4.开发风格:React推荐jsx+inline风格在js中同时写html和css.Vue使用webpack+vue-loader单文件组件格式。HTML、js、css在同一个文件中。你知道Vue模板编译的原理吗?能简单说明一下吗?简单的说,Vue的编译过程就是将模板转换成渲染函数的过程。它会经历以下几个阶段:生成AST树优化codegen首先解析模板,生成AST语法树(一种描述整个模板的JavaScript对象形式)。使用大量正则表达式解析模板,遇到标签和文本时,会执行相应的钩子进行相关处理。Vue的数据是响应式的,但并不是模板中的所有数据都是响应式的。有些数据在第一次渲染后不会发生变化,对应的DOM也不会发生变化。那么优化过程就是深度遍历AST树,根据相关条件标记树节点。我们可以跳过这些标记节点(静态节点)的比较,这在运行时极大地优化了模板。编译的最后一步是将优化后的AST树转换为可执行代码。简而言之,就是先将Vue.js的模板编译转化为AST树,然后渲染函数返回VNode(Vue的虚拟DOM节点)。详细步骤如下:首先,通过compile编译器将模板编译成AST语法树(抽象语法树是源代码抽象语法结构的树表示),compile是createCompiler的返回值,createCompiler用于创建编译器。此外,compile还负责合并选项。然后,AST会通过generate(将AST语法树转化为render函数字符串的过程)得到render函数。render的返回值是VNode,也就是Vue的虚拟DOM节点,里面包含(标签名,子节点,文本等)明白nextTick了吗?异步方法,异步渲染的最后一步,与JS事件循环密切相关。主要使用宏任务和微任务(setTimeout、promises),定义一个异步方法,多次调用nextTick将方法存入队列,通过异步方法清空当前队列。再说说Vue的生命周期。什么时候调用?beforeCreate:实例初始化后,数据观察前调用。created:创建实例后调用。实例完成:数据观察,属性和方法的操作,watch/event事件回调。None$el.beforeMount:挂载前调用,第一次挂载时调用相关render函数:替换为新创建的vm.$el,挂载到实例上后调用hook。beforeUpdate:在数据更新前调用,发生在虚拟DOM重新渲染打补丁时,之后会调用changehook。updated:虚拟DOM由于数据变化而被重新渲染和打补丁,之后会调用changehook。beforeDestroy:在实例销毁之前调用,实例仍然可用。destroyed:实例销毁后调用。调用后,Vue实例指示的所有内容都将被解除绑定,所有事件监听器和所有子实例都将被移除。每个生命周期内可以做什么?created:实例已经创建,因为是最早触发的,所以可以进行一些数据和资源的请求。mounted:实例已经挂载,可以进行一些DOM操作。beforeUpdate:你可以在这个钩子中进一步改变状态而不触发重新渲染。updated:可以执行依赖于DOM的操作,但要避免改变状态,这可能会导致更新的无限循环。destroyed:可以进行一些优化操作,清除定时器,解除绑定事件。ajax放在哪个生命周期?:一般放在mounted中保证逻辑统一,因为生命周期是同步执行的,ajax是异步执行的。单一服务端渲染ssr也放在created里面,因为服务端渲染不支持mounted方法。什么时候使用beforeDestroy?:当前页面使用了$on,需要解绑事件。清除定时器。取消绑定事件,滚动mousemove。你写过自定义指令吗?原理是什么?Instructions本质上是装饰器,是Vue对HTML元素的扩展,为HTML元素添加自定义函数。vue在编译DOM时,会找到指令对象,并执行指令的相关方法。自定义指令有五个生命周期(也叫钩子函数),分别是bind、inserted、update、componentUpdated和unbind1。bind:只调用一次,当指令第一次绑定到一个元素时。可以在这里进行一次性的初始化设置。2.inserted:绑定元素插入到父节点时调用(只保证父节点存在,不一定插入到文档中)。3.update:绑定元素的模板更新时调用,不管绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。4.componentUpdated:当绑定元素所在的模板完成一个更新周期时调用。5.unbind:只调用一次,当指令与元素解除绑定时。v-show和v-if有什么区别?v-if是真正的条件渲染,因为它将确保条件块内的事件侦听器和子组件在切换期间被适当地销毁和重建;也很懒惰:如果在初始渲染时条件为假,什么也不做-条件块不会开始渲染,直到条件第一次变为真。v-show更简单-无论初始条件如何,元素始终呈现,并且根据CSS“显示”属性简单地切换。因此,v-if适用于运行时很少改变条件,不需要频繁切换条件的场景;v-show适用于需要非常频繁切换条件的场景。Vue组件之间的通信方式有哪些?Vue组件之间的通信是面试中经常考到的知识点之一。这个问题有点类似于开放式问题。你回答的方法越多,你得到的分数就越多,这表明你对Vue.js的熟练程度更高。Vue组件之间的通信仅指以下三种通信:父子组件通信、代际组件通信、兄弟组件通信。下面我们将分别介绍每种通信方式,并说明该方式适用于哪些类型的组件通信。(1)props/$emit适用于父子组件通信。这种方法是Vue组件的基础。相信大部分同学都听过,这里就不举例了。(2)ref和$parent/$children适用于父子组件通信ref:如果用在普通DOM元素上,则引用指向DOM元素;如果用在子组件上,则引用指向组件实例$parent/$children:访问parent/childinstance(3)EventBus($emit/$on)适用于父子、代际、兄弟组件通信这个方法使用一个空的Vue实例作为中央事件总线(eventcenter),用于触发事件和监听事件以实现任何组件之间的通信,包括父子组件、代际组件和兄弟组件。(4)$attrs/$listeners适用于代际组件通信$attrs:包含父作用域中prop无法识别(获取)的特性绑定(类和样式除外)。当一个组件没有声明任何props时,所有的父作用域绑定(除了class和style)都会被包含在这里,内部组件可以通过v-bind="$attrs"传递。通常与inheritAttrs选项结合使用。$listeners:包含父作用域中的v-on事件监听器(没有.native装饰器)。它可以将v-on="$listeners"传递给内部组件(5)provide/inject适用于代际组件通信。在祖先组件中通过provider提供变量,然后在后代组件中通过inject注入变量。provide/injectAPI主要解决跨层组件之间的通信问题,但其使用场景主要是子组件获取上层组件的状态,跨层之间建立主动提供和依赖注入的关系级组件。(6)Vuex适用于父子、代际、兄弟组件通信。Vuex是专门为Vue.js应用开发的状态管理模型。每个Vuex应用程序的核心都是商店。“商店”基本上是一个容器,其中包含应用程序的大部分状态(state)。Vuex的状态存储是响应式的。当Vue组件从store中读取状态时,如果store中的状态发生变化,相应的组件将相应地高效更新。更改存储中状态的唯一方法是显式提交更改。这使我们能够轻松跟踪每个状态更改。Vue如何使用vm.$set()解决对象的new属性无法响应的问题?由于现代JavaScript的限制,Vue无法检测到对象属性的添加或删除。由于Vue在初始化实例时会对属性进行getter/setter转换,所以属性必须存在于数据对象上,Vue才能将其转换为响应式。但是Vue提供了Vue.set(object,propertyName,value)/vm.$set(object,propertyName,value)给对象添加响应式属性。框架本身是如何实现的?我们查看对应的Vue源码:vue/src/core/instance/index.jsexportfunctionset(target:Array|Object,key:any,val:any):any{//target是一个数组if(Array.isArray(target)&&isValidArrayIndex(key)){//修改数组的长度,避免索引>数组长度导致splcie()执行错误target.length=Math.max(target.length,key)//使用数组的拼接mutation方法触发响应target.splice(key,1,val)returnval}//key已经存在,直接修改属性值if(keyintarget&&!(keyinObject.prototype)){target[key]=valreturnval}constob=(target:any).__ob__//target本身不是响应式数据,直接赋值if(!ob){target[key]=valreturnval}//属性的响应式处理defineReactive(ob.value,key,val)ob.dep.notify()returnval}从上面的源码我们可以看出vm.$set的实现原理是:如果target是一个数组,直接使用数组的拼接方式触发相应的公式;如果target是对象的话,会先判断属性是否存在,对象是否有响应。最后,如果要对属性进行响应式处理,需要调用defineReactive方法进行响应式处理(defineReactive方法为当Vue初始化对象时,它使用Object.defineProperty为对象属性动态添加getter和setter。虚拟DOM的优点和缺点是什么?优点:保证性能下限:框架的虚拟DOM需要适配上层API可能产生的任何操作,其部分DOM操作的实现必须是通用的,因此其性能不高最佳的;但是相比粗糙的DOM运行性能要好很多,所以框架的虚拟DOM至少可以保证你在没有手动优化的情况下仍然可以提供良好的性能,也就是保证性能的下限;无需手动操作DOM:我们不再需要手动操作DOM,只需要编写View-Model的代码逻辑,框架将虚拟DOM和数据双向绑定,帮助我们更新视图可预测的方式,大大提高我们的开发效率;跨平台:VirtualDOM本质上是JavaScript对象,DOM与平台强相关。相比之下,虚拟DOM可以更方便的跨平台操作,比如服务端渲染,weex开发等。缺点:无法优化到极致:虽然虚拟DOM+合理的优化足以应对绝大部分应用的性能需求,但在一些对性能要求极高的应用中,无法针对虚拟DOM进行极致优化。虚拟DOM的原理是什么?虚拟DOM的实现原理主要包括以下三部分:利用JavaScript对象模拟真实DOM树,抽象真实DOM;diff算法——比较两个虚拟DOM树之间的差异;pach算法-将两个虚拟DOM对象之间的差异应用于真实的DOM树。如果你对以上3部分不是很了解,可以看看本文作者写的另一篇详细讲解虚拟DOM的文章《深入剖析:Vue核心之虚拟DOM》你对Vue项目做了哪些优化?如果你还没有对Vue项目进行过优化和总结,可以参考本文作者的另一篇文章《 Vue 项目性能优化 — 实践指南 》。文章主要从3大22小方面详细介绍了如何优化Vue项目。(1)代码层面的优化v-if和v-show区分使用场景与computed和watch场景v-for遍历必须给item添加key,避免同时使用v-if长列表性能优化事件破坏图片资源lazy加载路由第三方插件的延迟加载按需引入无限列表性能优化服务端渲染SSR或预渲染(二)Webpack层面的优化Webpack对图片进行压缩,减少冗余代码,从ES6到ES5提取常用代码模板预编译提取ComponentCSS优化SourceMap构建结果输出分析Vue项目编译优化(三)基础Web技术优化启用gzip压缩浏览器缓存CDN使用ChromePerformance寻找性能瓶颈