vue高频面试题

1. vue的基本原理是什么?

当 一 个 Vue 实 例 创 建 时 , Vue 会 遍历data 中的属性,用Object.defineProperty ( vue3.0 使 用proxy )将它们转为getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

2.双向数据绑定的原理

Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

首先对data执行响应化处理,在Observe中劫持所有属性,同时对complie中对模板进行编译,找到动态绑定的数据,从data中获取并且初始化视图,同时定义watcher和更新函数,通常data中会有多个watcher,因此定义一个Dep来管理这些watcher,当监听到Observe中有数据变化时会通知Dep,然后由Dep来通知所有的watcher去触发更新函数,最终更新视图。

3.MVVM、MVC、MVP 的区别

MVC、MVP 和 MVVM 是三种常见的软件架构设计模式,主要通过分离关注点的方式来组织代码结构,优化开发效率。

  • MVVM
    MVVM 分为 Model、View、ViewModel:Model 代表数据模型,数据和业务逻辑都在Model 层中定义;View 代表 UI 视图,负责数据的展示;
    ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
    Model 和 View 并无直接关联,而是通过ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当Model中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
    这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注于数据的维护操作即可,而不需要自己操作DOM。
  • MVC
    MVC 通过分离 Model、View 和 Controller 的方式来组织代码结构。
    View 负责页面的显示逻辑,Model 负责存储页面的业务数据,以及对相应数据的操作。并且 View 和Model 应用了观察者模式,当 Model 层发生改变的时候它会通知有关View 层更新页面。
    Controller 层是 View 层和 Model 层的纽带,它主要负责用户与应用的响应操作,当用户与页面产生交互的时候,Controller 中的事件触发器就开始工作了,通过调用 Model 层,来完成对Model的修改,然后 Model 层再去通知 View 层更新。
  • MVP
    MVP 模式与 MVC 唯一不同的在于 Presenter 和Controller。在MVC 模式中使用观察者模式,来实现当Model 层数据发生变化的时候,通知 View 层的更新。这样 View 层和Model 层耦合在一起,当项目逻辑变得复杂的时候,可能会造成代码的混乱,并且可能会对代码的复用性造成一些问题。MVP 的模式通过使用Presenter来实现对 View 层和 Model 层的解耦。MVC 中的Controller 只知道Model 的接口,因此它没有办法控制 View 层的更新,MVP 模式中,View 层的接口暴露给了 Presenter 因此可以在Presenter中将Model 的变化和 View 的变化绑定在一起,以此来实现View和Model 的同步更新。这样就实现了对View 和Model 的解耦,Presenter 还包含了其他的响应逻辑。

4.MVVM的优缺点

  • 优点
    分离视图(View)和模型(Model),降低代码耦合度,提⾼视图或者逻辑的重⽤性: ⽐如视图(View)可以独⽴于Model 变化和修改,⼀个 ViewModel 可以绑定不同的"View"上,当View 变化的时候Model不可以不变,当 Model 变化的时候 View 也可以不变。你可以把⼀些视图逻辑放在⼀个 ViewModel⾥⾯,让很多view 重⽤这段视图逻辑提⾼可测试性: ViewModel 的存在可以帮助开发者更好地编写测试代码
    ⾃动更新dom: 利⽤双向绑定,数据更新后视图⾃动更新,这也是十分方便的
  • 缺点
    Bug 很难被调试: 因为使⽤双向绑定的模式,当界⾯异常了,可能是 View 的代码有 Bug,也可能是Model 的代码有问题。数据绑定的声明是指令式地写在 View 的模版当中的,这样没有办法打断点,虽然使⽤⽅便了也很容易保证了数据的⼀致性,当时⻓期持有,不释放内存就造成了花费更多的内存
    对于⼤型的图形应⽤程序,视图状态较多,ViewModel 的构建和维护的成本都会⽐较⾼。

5.vue2和vue3有什么区别

  • 双向数据绑定原理不同: vue3重写了响应式系统,使用proxy代替了Object.defineProperty,实现了更高效的变化侦测
  • API类型不同 :vue2:vue2使用选项类型api,选项型api在代码里分割了不同的属性:data,computed,methods等。
    vue3:vue3使用组合式api,使用方法来分割,相比于v2,v3使用属性来分组,这样代码会更加简便和整洁。
  • 是否支持碎片:支持多个根节点,不再强制要求单一的根节点
  • 定义数据变量和方法不同:vue2是把数据放入data中,方法写在methods中,vue3就需要使用一个新的setup()方法,这个方法在组件初始化构造的时候触发。相当于vue2的创建前和创建后的钩子。
  • 生命周期钩子函数不同
    • vue2:
      beforeCreate 组件创建之前
      created 组件创建之后,组件初始化完毕,可以访问各种数据,获取接口数据等
      beforeMount 组价挂载到页面之前执行
      mounted 组件挂载到页面之后执行,dom已创建,可用于获取访问数据和dom元素;访问子组件等
      beforeUpdate 组件更新之前,此时view层还未更新,可用于获取更新前各种状态
      updated 组件更新之后,完成view层的更新,更新后,所有状态已是最新
    • vue3:
      setup 开始创建组件
      onBeforeMount 组价挂载到页面之前执行
      onMounted 组件挂载到页面之后执行
      onBeforeUpdate 组件更新之前
      onUpdated 组件更新之后
  • 指令和插槽不同
    • vue2:可以直接使用slot;v-for与v-if在vue2中优先级高的是v-for指令,而且不建议一起使用。
    • vue3:vue3中必须使用v-slot的形式;vue3中v-for与v-if,只会把当前v-if当做v-for中的一个判断语句,不会相互冲突;;vue3中移除v-on.native修饰符;vue3中移除过滤器filter。

6.v-if 和 v-for 哪个优先级更高?如果同时出现,应如何优化?

v-for 优先于 v-if 被解析,如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能。

如果同时出现,一定要避免出现这种情况,需要在外层嵌套 template,在这一层进行v-if判断,然后在内部进行 v-for 循环。如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项。

7.父子组件生命周期执行的循序

父组件和子组件生命周期钩子执行顺序:
加载渲染过程:

父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
更新过程:

父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
销毁过程:

父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

8.slot 是什么?有什么作用?原理是什么?

slot 又名插槽,是 Vue 的内容分发机制,组件内部的模板引擎使用slot 元素作为承载分发内容的出口。插槽slot 是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。

slot 又分三类,默认插槽,具名插槽和作用域插槽。默认插槽:又名匿名插槽,当 slot 没有指定name 属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。

具名插槽:带有具体名字的插槽,也就是带有name 属性的slot,一个组件可以出现多个具名插槽。

作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。

实现原理:当子组件 vm 实例化时,获取到父组件传入的slot 标签的内容,存放在 vm.slot中,默认插槽为vm.slot 中,默认插槽为vm.slot中,默认插槽为vm.slot.default,具名插槽为 vm.slot.xxx,xxx为插槽名,当组件执行渲染函数时候,遇到slot标签,使用slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到 slot 标签,使用slot.xxx,xxx为插槽名,当组件执行渲染函数时候,遇到slot标签,使用slot 中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

9.Vue data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染吗?

不会立即同步执行重新渲染。Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行DOM 的更新。

Vue 在更新DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM 操作是非常重要的。然后,在下一个的事件循环 tick 中,Vue 刷新队列并执行实际(已去重的)工作。

10.$nextTick 原理及作用

Vue 的 nextTick 其本质是对 JavaScript 执行原理EventLoop的一种应用。

nextTick 的 核 心 是 利 用 了 如 Promise 、MutationObserver、setImmediate、setTimeout 的原生 JavaScript 方法来模拟对应的微/宏任务的实现,本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列。nextTick 不仅是 Vue 内部的异步队列的调用方法,同时也允许开发者在实际项目中使用这个方法来满足实际应用中对DOM 更新数据时机的后续逻辑处理

nextTick 是典型的将底层 JavaScript 执行原理应用到具体案例中的示例,引入异步更新队列机制的原因∶

如果是同步更新,则多次对一个或多个属性赋值,会频繁触发UI/DOM的渲染,可以减少一些无用渲染同时由于 VirtualDOM 的引入,每一次状态发生变化后,状态变化的信号会发送给组件,组件内部使用 VirtualDOM 进行计算得出需要更新的具体的 DOM 节点,然后对 DOM 进行更新操作,每次更新状态后的渲染过程需要更多的计算,而这种无用功也将浪费更多的性能,所以异步渲染变得更加至关重要。

Vue 采用了数据驱动视图的思想,但是在一些情况下,仍然需要操作DOM。有时候,可能遇到这样的情况,DOM1 的数据发生了变化,而DOM2需要从 DOM1 中获取数据,那这时就会发现DOM2 的视图并没有更新,这时就需要用到了 nextTick 了。

由于 Vue 的 DOM 操作是异步的,所以,在上面的情况中,就要将DOM2获取数据的操作写在$nextTick 中。

所以,在以下情况下,会用到 nextTick:在数据变化后执行的某个操作,而这个操作需要使用随数据变化而变化的 DOM 结构的时候,这个操作就需要方法在nextTick()的回调函数中。

在 vue 生命周期中,如果在 created()钩子进行DOM 操作,也一定要放在 nextTick()的回调函数中。

因为在 created()钩子函数中,页面的 DOM 还未渲染,这时候也没办法操作 DOM,所以,此时如果想要操作 DOM,必须将操作的代码放在nextTick()的回调函数中。

相关推荐
IT小哥哥呀44 分钟前
《纯前端实现 Excel 导入导出:基于 SheetJS 的完整实战》
前端·excel
文心快码BaiduComate1 小时前
CCF程序员大会码力全开:AI加速营决赛入围名单揭晓,12月6日大理见!
前端·百度·程序员
vivo互联网技术1 小时前
从不足到精进:H5即开并行加载方案的演进之路
前端·h5·webview·客户端·大前端
我命由我123451 小时前
微信小程序 - 内容弹出框实现(Vant Weapp 实现、原生实现)
开发语言·前端·javascript·微信小程序·小程序·前端框架·js
hadage2331 小时前
--- vue标签中有key和没有的区别 ---
vue.js
裴嘉靖1 小时前
uniapp做的APP和安卓苹果做的什么区别
前端
申阳1 小时前
Day 20:开源个人项目时的一些注意事项
前端·后端·程序员
拾晚霞1 小时前
【Vue2-Niubility-Uploader】一个强大的 Vue2 文件上传解决方案
vue.js
天蓝色的鱼鱼1 小时前
大文件上传实战:基于Express、分片、Web Worker与压缩的完整方案
前端·node.js