【study】Vue经典面试题

503 阅读4分钟

1.说一下你对MVVM原理的理解

1.理解:
  • MVVM即是model,view,viewmodel

2.说一下vue响应式数据的原理

1. 核心点:
  • object.defineProperty
2. 理解:
  • 默认vue在初始化数据时,会给data中的属性使用object.defineProperty重新定义所有的属性,当页面获取到对应属性时,会进行依赖收集(收集当前组件的watcher),如果属性发生变化会通知相关依赖进行更新操作
3.原理:

image.png

3.说一下vue中如何检测数组的变化

1. 理解:
  • 使用了数组劫持的方式,重写了数组的方法
  • vue将data中的数组,进行了原型链的重写。指向了自己定义的数组原型方法,这样当调用数组api时,可以通知依赖更新。如果数组中包含引用类型,会对数组的引用类型再次进行监控。
2.原理:
  • 源码里面只拦截了数组的七种方法,因为只有这七种方法会改变原数组
  • 七种方法:push,pop,shift,unshift,splice,sort,reverse

image.png

4.说一下为何Vue采用异步渲染

1. 理解:
  • vue是组件更新
  • 如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染,为了性能考虑,vue会在本轮数据更新后,再去异步更新视图
2. 原理:

image.png

5.说一下nextTick实现原理

1. 理解:
  • nextTick方法主要是使用了宏任务和微任务,定义了一个异步的方法,多次调用nextTick方法会将方法保存在队列中,通过这个异步方法清空当前的队列,所以nextTick方法实际上就是异步方法
  • 一般会使用nextTick保证当前视图渲染完成
  • flushCallbacks
2. 原理:

image.png

6.说一下Vue中的computed特点

1. 理解:
  • 计算属性是具备缓存的,只有依赖的属性发生变化才会更新视图
2. computed和watch的区别

[www.cnblogs.com/jiajialove/…]

3. 原理:

image.png

7.说一下Vue中的watch中的deep:true是如何实现的

1. 理解:
  • 当用户设置watch:true时,如果当前的组件是数组类型,对监控每一项,将当前的watcher存到依赖中,这样数组中的对象变化也会通知数据更新
2.原理:

image.png

8.说一下Vue中的生命周期

1. 生命周期图例

[cn.vuejs.org/v2/guide/in…]

2. 生命周期

image.png

9.说一下Vue请求接口放在哪个生命周期

1. 理解:
  • 在created的时候,视图中的dom还没有渲染出来,所以此时去操作dom节点,无法找到相关的元素
  • 在mounted中,因为此时dom已经渲染出来了,所以可以直接操作dom节点
  • 一般情况下,都放在mounted中,保证逻辑的统一性,因为生命周期是同步执行的,ajax是异步执行的
  • 服务端不支持mounted的写法,所以服务端一般放在created中

10.说一下何时需要使用beforeDestory

1. 理解:
  • 可能在当前页面中使用了$on方法,那需要在组件销毁前解绑。
  • 清楚自己定义的定时器
  • 解绑事件的绑定,例如scroll等等

11.说一下Vue模板中的编译原理

1. 理解:
  • 将template转化成render函数
  • ast语法树
  • 模板引擎的实现:with + new Function()

12.说一下v-if和v-show的区别

1.v-show:通过display:none和display:block之间切换
  • 1.切换时需要删除,插入节点开销大
  • 2.但是在初始化的时候,如果条件是false,是不会插入节点渲染的会节约性能
  • 总结:如果不是频繁的切换,渲染时条件渲染使用v-if
2. v-if:通过dom节点插入。删除来实现切换
  • 1.有更高的初始渲染开销,就算是false也会渲染
  • 2.但是在切换的时候只是改变样式,消耗少
  • 总结:在频繁切换的时候用v-show

13.说一下v-if和v-for为什么不能连用

  • v-for的优先级大于v-if
  • 连用每次循环都会使用一次v-if,性能不好
  • 可以在v-for外层加一个div或者template来使用v-if

14.说一下如何用Vnode描述一个dom结构

15.说一下Vue中的diff算法原理

1. 理解:
  • 1.先同级比较,在比较子节点
  • 2.先判断乙方有儿子一方没儿子的情况
  • 3.比较都有儿子的情况
  • 4.递归比较子节点

16.说一下v-for中为什么要有key

1. 理解:
  • 唯一标志,不加的话删除会出错
  • 尽量不要使用索引作为key,不唯一

17.说一下你对keep-alive的理解

1. 理解:
  • keep-alive缓存不活动的组件的状态
2.作用:
  • 避免多次重复渲染降低性能
3.知识点:
  • include: 匹配组件被缓存
  • exclude: 和1相反,除了...都被缓存
  • max: 数字,最多可以缓存几个组件
  • 给Router路由,缓存部分页面,访问使用$route.meta.keepAlive
// app.vue
<template>
<!-- vue2写法 -->
 <keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
  </keep-alive>
  <router-view v-if="!$route.meta.keepAlive"></router-view>

<!-- vue3写法 -->
  <router-view v-slot = "{ Component }">
    <keep-alive>
      <component :is="Component" v-if="$route.meta.keepAlive"></component>
    </keep-alive>
  </router-view>
  <router-view v-slot = "{ Component }">
    <component :is="Component" v-if="!$route.meta.keepAlive"></component>
  </router-view>
</template>

<style lang="scss">
#app {
  text-align: center;
}
</style>

image.png

18.说一下判断空对象的方法

1. json.stringify
Json.stringify(obj) === '{}'
返回值是truefalse
2. for...in
function hasObj(obj) {
  for (let  key in obj) {
    return false // obj不是空的返回false
  }
  return true
}
3.Object.getOwnPropertyNames
// Object.getOwnPropertyNames
// 获取到对象中的属性名,存到一个数组中
var obj = {
  name: '棠梨煎雪1226'
}
let res = Object.getOwnPropertyNames(obj)
// ['name']
// 判断数组长度是否为0,即可判断对象是否为空
console.log(res.length === 0) // 是true还是false
4.Object.keys
// Object.keys
// 获取对象中所有可枚举的字符串的数组
var obj = {
  name: '棠梨煎雪1226'
}
let res = Object.keys(obj)
// ['name']
// 判断数组长度是否为0,即可判断对象是否为空
console.log(res.length === 0) // 是true还是false
5.hasOwnProperty
// hasOwnProperty
// 检测属性是否在对象实例中
function hasObj(obj) {
  for (let  key in obj) {
    if (obj.hasOwnProperty(key)) {
       return false 
    }
  }
  return true
}

19.说一下vue插槽slot

1.默认插槽
  • 直接留个solt即可,在组件内写内容
2.具名插槽
父组件:
第一种:<template #tljx>
第二种:<template v-slot:tljx>

子组件
<slot name="tljx">
3.作用域插槽
子组件里面的东西放在父组件使用
子 ----> 父

父组件:
<template v-solt:default="子组件传的值/tljx">

子组件:
<slot v-bind:tljx="定义的数据/要传过去的数据"

20.Vue异步组件,按需加载

1.vue.component
父组件:
引入子组件渲染:
<children></children>

第一种:
components:{
  children:()=>import ('./children')
}

第二种:
const children = () => {
  component:import ('./children')
}
components:{
 children
}
2.is
封装多个子组件的思想
通过传不同的值来渲染不同的组件

<component :is="COMPONENT_NAME"> </component>
COMPONENT_NAME,动态值