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

InterviewQuestions-20+Vue面试问题

时间:2023-03-31 15:27:53 vue.js

0.你能谈谈MVVM吗?MVVM是Model-View-ViewModel的缩写,就是将MVC中的Controller进化为ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View层和Model层之间的桥梁。数据将绑定到viewModel层并自动将数据呈现到页面。当视图发生变化时,会通知viewModel层更新数据。1、简单说说Vue2.x响应式数据的原理Vue在初始化数据的时候,会使用Object.defineProperty重新定义数据中的所有属性。当页面使用相应的属性时,会先收集依赖(收集当前组件的watcher),如果属性发生变化,会通知相关依赖进行更新(发布和订阅)。2、你知道Vue3.x响应式数据的原理吗?Vue3.x使用Proxy而不是Object.defineProperty。因为Proxy可以直接监听对象和数组的变化,拦截方式多达13种。并且作为新标准,浏览器制造商将专注于持续的性能优化。?Proxy只会代理第一层对象,那么Vue3是如何处理这个问题的呢??  判断是否有Reflect的返回值。实现了深度观察。?监控数组时,get/set可能会被触发多次,那么如何防止多次触发呢??  我们可以判断key是否为当前代理对象target自身的属性,或者旧值是否等于新值,只有满足以上两个条件之一才有可能执行触发器.3.下面说说在vue2.x中如何通过函数劫持和重写数组方法来监听数组的变化。Vue在data中重写了数组的原型链,指向自己定义的数组原型方法。这样调用arrayapi的时候,就可以通知依赖更新了。如果数组中包含引用类型,则会再次监控数组中引用类型的递归遍历。这样就实现了监听数组变化。4.你知道nextTick吗?实现原理是什么?在下一个DOM更新周期结束后执行的延迟回调。nextTick主要使用宏任务和微任务。根据执行环境尝试使用PromiseMutationObserversetImmediate。如果以上都不起作用,请使用setTimeout定义一个异步方法。多次调用nextTick会将方法存入队列,通过这个异步方法清空当前队列。5.说说Vue的生命周期。beforeCreate是newVue()之后触发的第一个钩子。当前阶段,data、methods、computed、watch上的数据和方法都无法访问。created发生在实例创建之后,当前阶段已经完成了数据观察,即可以使用和更改数据,更改这里的数据不会触发update函数。可以做一些初步的数据获取,现阶段还不能和Dom交互。如果你愿意,你可以通过vm.$nextTick访问Dom。beforeMount发生在挂载之前,模板模板还没有被导入渲染函数进行编译之前。目前阶段,虚拟Dom已经创建完成,即将开始渲染。此时也可以更改数据而不触发更新。mounted发生在挂载完成之后。现阶段挂载了真正的Dom,数据双向绑定,可以访问到Dom节点,可以通过$refs属性来操作Dom。beforeUpdate发生在更新之前,即响应式数据更新时,在虚拟dom重新渲染之前触发。您可以在当前阶段更改数据而不会导致重新渲染。updated发生在更新完成后,当前stage组件Dom已经更新完毕。小心避免在这段时间内更改数据,因为这可能会导致更新无限循环。beforeDestroy发生在实例销毁之前,当前阶段实例可以完全使用,此时我们可以进行收尾工作,比如清空定时器。destroyed发生在实例销毁之后,此时只剩下dom壳。组件拆了,数据绑定拆了,监听器拆了,子实例全部销毁了。6、你们的接口请求一般放在哪个生命周期?接口请求一般放在mounted中,但是需要注意的是服务端渲染时不支持mounted,需要放在created中。7.说一下,Computed和WatchComputed本质上是一个带缓存的watcher,当依赖的属性发生变化时,view就会更新。适用于计算对性能消耗较大的计算场景。当表达式过于复杂时,在模板中放入过多的逻辑会使模板难以维护,可以在计算属性中处理复杂的逻辑。Watch没有缓存,更多的是一个观察功能,可以监听某些数据并执行回调。当我们需要对对象中的属性进行深度监控时,可以开启deep:true选项,这样对象中的每一项都会被监控到。这会导致性能问题。优化的话,可以用字符串的形式来监控。如果没有写入组件,不要忘记使用unWatch手动退出。8、先说一下v-if和v-show的区别。当条件不成立时,v-if不会渲染DOM元素,v-show对样式(display)进行操作,切换当前DOM的显示和隐藏。9、为什么组件中的数据是一个函数?如果多次重用一个组件,将创建多个实例。本质上,这些实例都使用相同的构造函数。如果data是一个对象,那么这个对象就是一个引用类型,会影响到所有的实例。所以为了保证不同组件实例之间数据不冲突,数据必须是一个函数。10、说说v-model的原理v-model本质上是一个语法糖,可以看成是值+输入法的语法糖。可以通过model属性的prop和event属性进行自定义。原生的v-model会根据不同的标签生成不同的事件和属性。11、Vue事件绑定原理先说下原生事件绑定是通过addEventListener绑定到真实元素上,而组件事件绑定是通过Vue自定义的$on实现的。大牛博客:https://weibo.com/u/699881829712。你知道Vue模板编译的原理吗?能简单说明一下吗?简单的说,Vue的编译过程就是将模板转换成渲染函数的过程。它会经历以下几个阶段:生成AST树优化codegen首先解析模板,生成AST语法树(一种描述整个模板的JavaScript对象形式)。使用大量正则表达式解析模板,遇到标签和文本时,会执行相应的钩子进行相关处理。Vue的数据是响应式的,但并不是模板中的所有数据都是响应式的。有些数据在第一次渲染后不会发生变化,对应的DOM也不会发生变化。那么优化过程就是深度遍历AST树,根据相关条件标记树节点。我们可以跳过这些标记节点(静态节点)的比较,这在运行时极大地优化了模板。编译的最后一步是将优化后的AST树转换为可执行代码。大牛博客:https://weibo.com/u/699881829713。Vue2.x和Vue3.x渲染器的diff算法分别说明。简单的说,diff算法有如下对等比较的过程,然后比较子节点,先判断当一方有子节点,另一方没有子节点时(如果新的孩子没有子节点,则去掉旧的孩子nodes)comparethecasewherethere'sallchildnodes(corediff)递归比较子节点和普通Diff两棵树。时间复杂度为O(n^3),但是在实践中我们很少跨层移动DOM,所以Vue优化Diff从O(n^3)->O(n),只有当old和newchildren存在时为多个子节点,需要使用核心Diff算法进行同级比较。Vue2的核心Diff算法采用了双端比较的算法。同时从新旧孩子两端开始比较,根据key值找到可重用的节点,然后进行相关操作。与React的Diff算法相比,可以减少相同情况下移动节点的次数,减少不必要的性能损失,更加优雅。Vue3.x借鉴了ivi算法和inferno算法在创建VNode时判断其类型,在mount/patch过程中使用位运算判断VNode的类型。在此基础上,配合核心Diff算法,使得性能较Vue2.x有所提升。(具体实现可以结合Vue3.x源码查看)该算法同样采用了动态规划的思想求解最长递归子序列。大牛博客:https://weibo.com/u/699881829714。说一下虚拟Dom的作用和关键属性,因为在浏览器中操作DOM是非常昂贵的。频繁操作DOM会导致一定的性能问题。这就是虚拟Dom的原因。Vue2的VirtualDOM借鉴了开源库snabbdom的实现。VirtualDOM的本质是用一个原生的JS对象来描述一个DOM节点。它是对真实DOM的抽象层。(即源码中的VNode类,定义在src/core/vdom/vnode.js中。)VirtualDOM映射到真实DOM要经过VNodecreate、diff、patch等阶段。”关键的作用是尽可能多地重用DOM元素。”当新旧子节点中的节点只是顺序不同时,最好的操作应该是通过移动元素的位置来达到更新的目的。新旧子节点中需要保存映射关系,以便在旧子节点中找到可复用的节点。key是节点在children中的唯一标识。15、你了解keep-alive吗?keep-alive可以实现组件缓存,切换组件时不会卸载当前组件。两个常用的属性include/exclude允许有条件地缓存组件。activated/deactivated两个生命周期用于了解当前组件是否处于活动状态。keep-alive也用到了LRU(LeastRecentlyUsed)算法。(又是数据结构和算法,原来算法在前端有那么多应用。)16.Vue中组件生命周期的调用顺序先说说组件的调用顺序先父后子,以及组件的调用顺序渲染是先子后父。组件的销毁操作是先父后子,销毁顺序是先子后父。加载渲染进程parentbeforeCreate->parentcreated->parentbeforeMount->childbeforeCreate->childcreated->childbeforeMount->childmounted->parentmounted子组件更新流程parentbeforeUpdate->childbeforeUpdate->childupdated->parentupdatedparentcomponentupdateprocessparentbeforeUpdate->parentupdateddestructionprocessparentbeforeDestroy->childbeforeDestroy->childdestroyed->parentdestroyed17.Vue2.x组件通信方式有哪些?父子组件通信Parent->childprops,child->parent$on,$emit获取父子组件实例$parent,$childrenRef获取实例调用组件的属性或方法提供,inject官方不推荐,但是写组件库的时候非常常用的兄弟组件通信EventBus实现跨组件通信Vue.prototype.$bus=newVueVuex跨级组件通信Vuex$attrs,$listenersProvide,inject18.SSR你懂吗?SSR即服务端渲染,即在服务端完成Vue在客户端将标签渲染成HTML的工作,然后将HTML直接返回给客户端。SSR具有更好的SEO和更快的首屏加载优势。但是,它也有一些缺点。比如我们的发展条件会受到限制。服务器端渲染只支持两个钩子,beforeCreate和created。当我们需要一些外部扩展库时,需要进行特殊处理。服务器端渲染应用程序也需要在Node.js运行环境中。另外,服务器会有更大的负载要求。19、你做过哪些Vue性能优化?在编码阶段尽量减少数据中的数据,数据中的数据会添加getter和setter,并收集对应的watcher。v-if和v-for不能一起使用。如果需要使用v-for给每个元素绑定事件,使用事件代理SPA页面采用keep-alive缓存组件更多情况下,使用v-if代替v-showkey,保证唯一使用路由的懒加载,异步组件防抖、节流第三方模块按需导入长列表动态滚动到可见区域加载图片懒加载SEO优化预渲染服务端渲染SSR打包优化压缩代码TreeShaking/ScopeHoisting使用CDN加载第三方-partymodules多线程打包happypacksplitChunks提取公共文件sourceMap优化用户体验骨架屏PWA还可以使用缓存(客户端缓存),服务端缓存)优化,在服务端启用gzip压缩等(优化是个大工程,而且它会涉及到很多方面,这里是另外一个专栏的应用。)20.hash路由和history路由实现原理先说说location的值,hash其实就是th在URL中的#之后。History实际上是使用HTML5中提供的API实现的,主要包括history.pushState()和history.replaceState()。