前端vue面试题,有答案面试题视频讲解(高效学习):进入学习vue中使用了哪些设计模式1.工厂模式-传入参数创建实例虚拟DOM根据不同的参数返回基本标签的Vnode和组件Vnode2.单例模式——整个程序只有一个实例。vuex和vue-router的插件注册方法install判断如果系统有实例则直接返回。3.发布订阅模式(Vue事件机制)4.观察者模式(响应式数据原理)5.装饰模式:(@decorator用法)6.策略模式策略模式指的是一个对象的行为,但是在不同的场景下,behavior有不同的实现方案——比如optionmergingstrategy你知道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将方法存入队列,通过异步方法清空当前队列。Computed实现原理Computed本质上是一个惰性求值观察者。Computed内部实现了一个lazywatcher,即computedwatcher。Computedwatcher不会立即求值,同时持有一个dep实例。它在内部标记计算属性是否需要通过this.dirty属性重新计算。当计算出的依赖状态发生变化时,它会通知惰性观察者。computedwatcher通过this.dep.subs.length判断是否有订阅者。如果是,它将重新计算,然后比较旧值和新值。如果它发生变化,将重新渲染。(Vue不仅要保证计算属性依赖的值发生变化,还要保证当计算属性最终计算出的值发生变化时,会触发渲染观察者重新渲染,这本质上是一种优化。)如果没有,就把这个。脏=真。(当一个计算属性依赖于其他数据时,该属性不会立即重新计算,只有在以后需要在别处读取该属性时才会真正计算,即具有lazy(惰性计算)特性。)为什么Vue使用vm.$set()来解决对象的new属性无法响应的问题?能说说下面代码的实现原理吗?1)为什么Vue使用vm.$set()来解决对象的new属性无法响应的问题?Vue使用Object.defineProperty实现双向数据绑定。初始化实例时,它会对属性执行getter/setter转换。该属性必须存在于数据对象上。为了让Vue把它转换成响应式的(这也导致Vue无法检测到对象属性的增删),所以Vue提供了Vue.set(object,propertyName,value)/vm.$set(object,propertyName,value)2)接下来我们看看框架本身是如何实现的?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)//使用拼接突变数组触发响应的方法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是一个数组,直接使用数组的splice方法触发对应的公式;如果目标是一个对象,首先会解释该属性是否存在,对象是否响应,最后如果要对该属性进行响应式处理,则需要调用defineReactive方法进行响应式处理。defineReactive方法是在Vue初始化对象时,使用Object.defineProperty为对象属性动态添加getter和对象属性。setter函数调用的方法v-show和v-if有什么区别?v-if是真正的条件渲染,因为它将确保条件块内的事件侦听器和子组件在切换期间被适当地销毁和重建;也很懒惰:如果在初始渲染时条件为假,什么也不做,并且是简单的基于CSS的“display”属性来切换。因此,v-if适用于运行时很少改变条件,不需要频繁切换条件的场景;v-show适用于需要非常频繁切换条件的场景.Vue组件之间通信有哪些方式?Vue组件之间通信是面试中经常考的知识点之一,这个问题有点类似开放题,回答的方法越多,加分越多get,说明你对Vue比较熟练,Vue组件之间的通信只指以下三种通信:父子组件通信,interg一代组件通信和兄弟组件通信。下面我们将分别介绍每种通信方式,并说明该方式适用于哪些类型的组件通信。(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中key有什么用?关键是每个vnode的唯一ID。依靠key,我们的diff操作可以更准确更快(diff节点对于简单的列表页面渲染也更快,但是会有一些隐藏的副作用,比如可能没有Transition效果,或者当某些节点有绑定数据时(form)state,会出现state错位。)diff算法过程中,会先对新旧节点进行端到端的交叉比较,当使用新节点的key时没有匹配到,与老节点比较,找到对应的老节点。更准确的说:因为key不是就地复用,所以在sameNode函数a.key===b.key比较中可以避免就地复用。所以它会更准确。如果不加key,会保留前一个节点的状态,会出现一系列的bug。更快:键的唯一性可以被Map数据结构充分利用。相对于遍历搜索的时间复杂度O(n),Map的时间复杂度仅为O(1)