Vue 前段面试题精选

一、【MVVM】
MVVM即model-view-viewModel的缩写,model是数据模型,vue是页面,vueModel也就是MVC的Controller演变而来的,vueModel作为model和vue之间的桥梁,数据会绑定到viewModel层并自动渲染到页面,视图变化的时候会通知viewModel层更新数据

二、【vue的双向数据绑定原理】
采用数据劫持结合发布者-订阅者的方法,通过Object.DefineProporty()劫持各个属性的settet,getter
Observe对数据对象递归遍历,都加上setter,getter,只要数据改变,就能监听到
Compile解析编译模板制冷,初始化页面视图,只要数据发生改变,收到消息,立马更新视图
MVVM做为数据绑定的入口,整合observe,compile,watcher三者,observe监听数据model的变化,compile解析编译模板指令,watcher做为compile和observe之间的桥梁,达到数据更新-视图变化,视图交互变化-数据model变更

三、【vue响应式数据原理】

vue2.x:
        vue在初始化数据时,会使用Object.DefineProporty()重新定义data的属性,当页面使用对应属性时,会进行依赖收集,若属性发生改变会通知相关依赖进行更新操作

vue3.x:

        用Proxy替代Object.DefineProporty(),因为proxy可以直接监听对象和数组的变化,有13种拦截方法,proxy只代理第一层,那30怎么办:判断当前reflect.get的返回值是否为Object,若是,再通过reactive方法做代理

四、【Vue中的mixins是什么】

mixins是一种可重用的代码的方式,它可以让我们在不同的Vue组件之间共享相同的Vue选项。

五、【vue2.0响应式缺陷】
Object.DefineProporty()无法监控数组下标的变化,导致通过数组下标添加元素不能实时响应
Object.DefineProporty()本身是可以监控到数组下标变化的,但是在vue中,从性能上考虑,就废弃了这个特性
Object.DefineProporty()只能劫持对象的属性,从而需要对每个对象、每个属性进行遍历,如果属性值是对象,还需要深度遍历

六、【vue3.0为啥使用proxy实现响应式】
Proxy可以劫持整个对象,并返回一个新的对象
Proxy不仅可以代理对象,还可以代理数组

七、【vue2.x中如何监听数组变化】
使用函数劫持的方式,重写了数组的方法,vue将data中的数组进行了原型链的重写,指向自己定义的数组原型方法,
这样当调用数组api时,可以通知依赖更新。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控,就实现了检测数组变化。

八、【nextTick实现原理是?】
vue通过异步队列控制DOM更新和nextTick回调函数先后执行的方式
在下次DOM更新循环结束之后执行延迟回调,nextTick主要使用了宏任务与微任务,根据执行环境分别尝试采用Promise,Mutation,Observe,setlmmediate 如果以上都不行则采用setTimeout定义一个会将方法存入队列中,通过这个异步方法清空当前队列

九、【Computed和Watch】
Computed的本质是一个具备缓存性质的Watcher,基于响应式依赖进行缓存,使用于计算比较消耗性的计算场景。
当表达式过于复杂时,在模板中放入过多的逻辑会让模板字符串难以维护,可以将复杂的逻辑放入计算属性中处理。
Watch没有缓存性,更多的是观察作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,可以打开deep:true选项

十、【v-if和v-show的区别】
当条件不成立时,v-if不会渲染DOM元素,v-show操作的是样式(display),切换当前DOM的显示和隐藏。

十一、【组件中的data为什么是一个函数】
一个组件被复用多次的话,也就会创建多个实例,本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用数据类型。所以为了保证不同组件实例的data不冲突,data必须是一个函数。

十二、【v-model的原理】
v-model本质就是一个语法糖,可以看成是value+input方法的语法糖。可以通过model属性的prop和event属性来进行自定义。原生的v-model,会根据标签的不同生成不同的事件和属性。

十三、【vue事件绑定原理】
原生时间绑定原理是通过addEventListener绑定给真实元素的,组件事件是通过Vue自定义的$on实现的。

十四、【VUE模板编译原理】
vue的编译过程就是将template转化为render函数的过程,分别以下三部:
第一步:将模板字符串转化成element ASTs(解析器)
第二步:对AST进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)
第三步:使用element ASTs 生成render函数代码字符串(代码生成器)
简单说,vue的编译过程就是将template转化为render函数的过程,会经历以下阶段:
生成AST树
优化
codegen
首先解析模板,生成AST语法树(一种用javascript对象的形式来描述整个模板) 使用大量的正则表达式对模板进行解析
遇到标签】文本的时候都会执行对应的钩子进行相关处理
vue的数据都是响应式的,但其实模板中并不是所有的数据都是响应式的,有一些数据首次渲染后就不会再变化,对应的DOM也不会变化。
那么优化过程就是深度遍历AST树,按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对他们的比对,对运行时的模板起到很大的优化作用
编译的最后一步就是将优化后的AST树转换为可执行的代码
十五、【vue2.x和3.x渲染器的diff算法】
diff算法的作用:用来修改DOM的一小段,不会引起dom树的重绘
diff算法的实现原理:diff算法将虚拟DOM的某个节点数据改变后生成新的的node节点与旧节点进行比较,并替换为新的节点,具体过程就是调用Patch方法,比较新旧节点,一边比较一边给真实DOM打补丁进行替换
简单来说,diff算法有以下过程
同级比较,再比较子节点
先判断一方有子节点一方 没有子节点的情况(如果新的children没有子节点,将旧的节点移除)
比较都有子节点的情况(核心diff)
递归比较子节点
正常diff两个树的时间复杂度是O(n3),但实际情况下我们很少会进行跨层级的移动DOM,所以vue将diff进行了优化,从O(n3)–>O(n),只有当新旧children都为多个子节点时才需要用核心的diff算法进行同层级比较。
Vue2的核心diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助Key值找到可复用的节点,再进行相关操作。
相比React的diff算法,同样情况下可以减少移动节点的次数,减少不必要的性能损耗,更加的优雅。
Vue3.x借鉴了ivi算法和inferno算法
在创建VNode时就确定其类型,以及在mount/patch的过程中采用位运算来判断一个VNode的类型,在这个基础之上再配合核心的Diff算法,使得性能上较Vue2.x有了提升(实际的实现可以结合Vue3.x的源码看)
该算法中还运用了动态规划的思想求解最长递归子序列

十六、【虚拟DOM & Key】
由于在浏览器中操作DOM是很昂贵的,频繁的操作DOM,会产生一定的性能问题,这就是虚拟DOM的产生原因。虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象状态变更时,记录新树与旧树的差异,最后把差异更新到真正的DOM中
Vue2的虚拟DOM借鉴了开源库Snabbdom的实现
虚拟dom的本质就是运用一个原生的JS对象去描述一个DOM节点,是对真实DOM的一层抽象。(也就是源码中的VNode类,它定义在src/core/vdom/vnode.js中)
虚拟dom映射到真实dom要经历VNode的create、diff、patch等阶段

a.key的作用是尽可能的复用DOM元素
b.新旧children中的节点只有顺序是不同的时候,最佳的操作应该是通过移动元素的位置来达到更新的目的,需要在新旧children的节点中保存映射关系,以便能够在旧children的节点中找到可复用的节点。key也就是children中节点的唯一标识。


【为何在v-for中使用key】
1.必须用key,且不能是index和random
2.diff算法通过tag和key来判断,是否是sameNode
3.减少渲染次数,提升渲染性能,高效更新虚拟Dom

十七、【Keep-alive】
keep-alive是vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁他们,keep-alive是一个抽象组件:它自身不会渲染成一个DOM元素,也不会出现在父组件链中。
在组件切换过程中,把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性
keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。
常用的两个属性include/exclude,允许组件有条件的进行缓存,两个生命周期activated/deactivated,采用得知当前组件是否处于活跃状态。
keep-alive中还运用了LRU(Least Recently Used)算法

十八、【Vue组件生命周期调用顺序】
组件的调用顺序都是先父后子,渲染完成的顺序是先子后父。
组件的销毁顺序是先父后子,销毁完成的顺序是先子后父。
加载渲染过程:
父beforeCreate --> 父created --> 父beforeMount --> 子beforeCreate -->子created --> 子beforeMount -->子mounted --> 父mounted
子组件更新过程:
父beforeUpdate --> 子beforeUpdated --> 子updated -->父updated
父组件更新过程:
父beforeUpdate --> 父updated
销毁过程:
父beforeDestroy --> 子beforeDestroy --> 子destroyed --> 父destroyed

十九、【vue2.x组件通信方式】
父子组件通信
父–>子 props, 子–>父 o n , on,on,emit
获取父子组件实例 $parent c h i l d r e n R e f 获取实例的方式调用组件的属性或者方法 p r o v i d e 、 i n j e c t 官方不推荐使用,但是写组件库时很常用兄弟组件通信 e v e n t b u s 实现跨组件通信 t h i s . children Ref获取实例的方式调用组件的属性或者方法 provide、inject官方不推荐使用,但是写组件库时很常用 兄弟组件通信 event bus 实现跨组件通信 this.childrenRef获取实例的方式调用组件的属性或者方法provide、inject官方不推荐使用,但是写组件库时很常用兄弟组件通信eventbus实现跨组件通信this.bus.o n t h i s . on this.onthis.bus.$emit
跨组件通信 vuex $atters $listeners provide、inject

二十、【vue性能优化】
尽量减少data中的数据,会增加setter,getter,会收集对应的watcher
data层级不要太多
v-if与v-for不要连用
spa页面采用keep-alive缓存组件
合理使用v-if v-show
key值保证唯一
自定义事件、DOM即时销毁
使用路由懒加载、异步组件
防抖、节流
第三方模块按需导入
长列表滚动到可视区域动态加载
图片懒加载
SEO优化
预渲染
服务端渲染 SSR
打包优化
压缩代码
使用cdn加载第三方模块

二十一、【react和vue比较】
1、component层面,web component和virtual DOM
2、数据绑定(vue双向 react单向)
3、vue有计算属性和watch
4、vue由于提供的direct特别是预置的directive因为场景开发更容易;react没有
5、生命周期函数名太长 directive

二十二、【组件中name的作用】
项目使用keep-alive时,可搭配组件name进行缓存过滤
DOM做递归组件时需要调用自身name
vue-devtools调试工具里显示的组件名称是由vue组件name决定的

二十三、【为什么官方说vue没有完全遵循MVVM思想?】
严格的MVVM要求View与Model不能直接通信,而vue提供了$refs这个属性,让model可以直接操作view,违反了这一规定,所以没有完全遵循MVVM

二十四、【vue单向数据流】
数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解。
注意:在子组件直接用v-model绑定父组件传过来的props这样是不规范的写法,开发环境会报警告。如果实在要改变父组件的props可以在data里面定义一个变量,并用prop的值初始化它,之后用$eimit通知父组件去修改

二十五、【经常遇到的浏览器兼容性问题有哪些?】
浏览器默认的margin和padding不同
IE6双边距bug
在IE6、IE7中元素高度超出自己设置的高度,原因是IE8以前的浏览器中会给元素设置默认的行高的高度导致的
min-height在IE6下不起作用
透明性IE用filter.Alpha(opacity=60),而其他主浏览器用opacity:0.6
input边框问题,去掉input边框一般用border:none就可以,由于IE6在解析input样式时的bug(优先级问题),在IE6下无效

二十六、【何时需要使用beforeDestory?】
解绑自定义事件
清除定时器
解绑自定义的DOM事件,如window scroll

二十七、【为何v-for使用key?】
必须用key, 不能是index和random
diff算法通过tag和key来判断是否是相同节点
减少渲染次数,提高渲染性能

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值