前端面试题之vue篇

vue基础

vue的基本原理

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

双向数据绑定的原理

MVVM 双向绑定,达到数据变化 -> 试图更新;试图变化 -> 数据model变更
前端面试题之vue篇_第2张图片

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

由两个主要的部分组成

  • 监听器(Observer):对所有数据的属性进行监听
  • 解析器(Compiler):对每个元素节点的指令进行扫描和解析,根据指令模板替代数据,以及绑定相应的更新数据

过程如下(Vue为例)

  1. new Vue() 首先执行初始化,对data执行相应化处理,这个过程发生在Observer
  2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取数据并初始化视图,这个过程发生在Compile
  3. 同时定义一个更新函数updaterwatcher,将来对应的数据变化时watcher会调用更新函数
  4. 由于data的某个key在一个视图中可能出现多次,所以每个key都需要一个管家Dep来管理多个watcher
  5. 将来data中的数据一旦发生变化,会先找到对应的Dep,通知所有watcher执行更新函数

Object.defineProperty() 来进行数据劫持有什么缺点

  1. Object.defineProperty() 是一开始就遍历对象进行监听,所以检测不到对象属性的添加和删除
  2. 数据的API方法无法监听到,例如push、pop方法等监听不到
  3. 需要对每个属性进行遍历监听,如果嵌套的对象层级比较深,则会影响性能

MVVM、MVC、MVP的区别

MVVM
MVVM分为model、view、viewModel

  • Model代码数据模型,数据和业务逻辑都在Model层中定义
  • view代表UI视图,负责数据的展示
  • viewModel负责监听Model中的数据的改变并且控制视图的更新,处理用户的交互操作

Model和View并无关联,而是通过viewModel来进行联系的,Model和View之间有着数据绑定的关系,Model中的数据发生改变时会触发View层的更新,View中数据的变化也会更新到Model层中。

这种模式实现了Model和View的数据自动同步,因此开发者只需要专注于数据的维护,而不用操作DOM

MVC
MVC是Model、View和Controller的方式来组织代码结构,其中的View负责显示逻辑,Model负责业务数据以及数据操作。Model数据发生变化的时候会通知有关View层更新页面,Controller是View和Model之间的纽带,带用户页面发生交互的时候,COntroller中的事件触发器开始工作,通过调用Model层来完成Model的修改,Model再去更新View层

前端面试题之vue篇_第3张图片
MVP
MVC中很多逻辑会在View层和Model层耦合,代码复杂的时候可能会造成代码的混乱。MVP模式和MVC的不同在于Presenter和Controller。Presenter来实现对View层和Model层的解耦,在MVC中Controller只知道Model中的接口,不知道View中的逻辑,然而在MVP模式中,View层的接口同样暴漏给了Presenter,因此可将Model层的变化和View的变化绑定在一起,实现View和Model的同步更新。

computed和watch的区别

对于Computed

  • 它支持缓存,只有依赖的数据发生变化的时候才会重新计算
  • 不支持异步,当Computed中有异步操作的时候,无法监听数据的变化

对于watch

  • 它不支持缓存,数据发生变化时,它就会触发相应的操作
  • 支持异步监听
  • 监听的函数接收两个参数,第一个参数是最新的值,第二个参数是变化之前的值

总结

  • computed依赖其他属性值,并且computed的值有缓存,只有依赖的值发生变化,才会重新计算computed的值
  • watch更多的是观察的作用,无缓存性,类似与某些数据监听的回调函数,每次监听的数据发生变化都会执行回调函数

slot 插槽

  • 默认插槽
<button type="submit">
  <slot>
    Submit <!-- 默认内容 -->
  </slot>
</button>
  • 具名插槽
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

使用具名插槽的方式

<BaseLayout>
  <template v-slot:header>
    <!-- header 插槽的内容放这里 -->
  </template>
</BaseLayout>

v-slot 有对应的简写 #,因此 可以简写为