Vue 面试题进阶(含底层源码原理)

前置 

  需要看过源码为基础,因为这些问题基本上都是从 源码中找到的答案,我只是顺便自己在看源码时记录了下来.

正文

1.Vue 的初始化过程(new Vue(options))都做了什么?

  • 处理组件配置项

    • 初始化根组件时进行了选项合并操作,将全局配置合并到根组件的局部配置上

    • 初始化每个子组件时做了一些性能优化,将组件配置对象上的一些深层次属性放到 vm.$options 选项中,以提高代码的执行效率

  • 初始化组件实例的关系属性,比如 $parent、$children、$root、$refs 等

  • 处理自定义事件

  • 调用 beforeCreate 钩子函数

  • 初始化组件的 inject 配置项,得到 ret[key] = val 形式的配置对象,然后对该配置对象进行响应式处理,并代理每个 key 到 vm 实例上

  • 数据响应式,处理 props、methods、data、computed、watch 等选项

  • 解析组件配置项上的 provide 对象,将其挂载到 vm._provided 属性上,如果 provide 是函数就用 call(vm) 方法 返回 provide 里面定义的对象

  • 调用 created 钩子函数

  • 如果发现配置项上有 el 选项,则自动调用 $mount 方法,也就是说有了 el 选项,就不需要再手动调用 $mount 方法,反之,没提供 el 选项则必须调用 $mount

  • 接下来则进入挂载阶段

  • 面试问题 

  • 1.父组件调用子组件自定义事件时,是谁在监听这个事件?

  • 答案: 子组件本身,也就是谁触发事件谁就监听,子组件会通过父组件获取 监听器,最终编译成 this.$emit(evenName,params)  this.$on(eventName,handelrFn)

  • 2.beforeCreate 期间能拿到数据吗?

  • 答案: 不能,因为数据初始化阶段是在 beforeCreate 之后执行

  • 3.provide 和 inject 原理

  • 答案:provide 其实不是真正的在根组件中注入,而是 子组件中的 inject 先根据 key值 生成数组,然后根据数组的长度依次遍历,并且向上级查找有没有 provide 这个配置选项,如果有那么就会看有没有 跟当前key 值 匹配,如果匹配的话 就会把value 值赋值给这个 key。如果没有 provide ,那么他会继续往上找

2.computed 缓存原理

computed 本身就是一个 watcher ,源码中在 vue 初始化阶段的 initComputed 函数中 ,创建了一个 watcher 实例,并传进去了一个 lazy ,lazy 是一个布尔值,lazy 本身是以常量声明的,所以不可更改,lazy 默认值为 true,然后 watcher 内部会以 lazy 在声明一个 dirty 属性,这个属性就是 computed 懒执行的根本原理,如果 watcher.dirty 为 true ,watcher 构造函数内部 会根据 watcher.evaluate 先将watcher.dirty 置为 false,再执行计算属性中的函数,并将其函数返回值 赋值给 watcher.value 属性中,这也就为什么计算属性中的函数要写 return 的原因,当 watcher.dirty 属性为 false 后,就不会在执行 watcher.evaluate 方法,也就不会在执行 计算属性中的函数,他最后会直接 return watcher.value 也就是计算属性中的函数执行结果,当页面更新时(也就是响应式派发更新的时候) set函数会调用 watcher 中的 update方法,在update方法中会将 dirty 再次更改为 true,然后此时 计算属性会重新执行

3.computed 和 watch 哪里不同?

其实computed 和 watch 都是一个 watcher ,真要说不同的话,我认为有三点

 ->1.computed 默认是懒执行,且不可更改(上面已经说过了)

 -> 2.使用场景方面,watch 可以执行一些异步操作,而 computed 大多数为同步操作,可以在 computed 内部的函数加个 async 试试,模板最终渲染为 [object Promise]

 -> 3. 当一个属性受多个属性影响的时候就需要用到 computed ,最典型的栗子:购物车商品结算的时候。当一条数据影响多条数据的时候就需要用 watch ,栗子:搜索数据

4. Vue.set( target<Array,Object> , key,val ) 都做了什么

因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi'),所以通过 Vue.set 为向响应式对象中添加一个 property,可以确保这个新 property 同样是响应式的,且触发视图更新。

  • 更新数组指定下标的元素:Vue.set(array, idx, val),内部通过 splice 方法实现响应式更新,target.splice(key, 1 , val)

  • 为对象添加一个新的响应式数据:调用 defineReactive 方法为对象增加响应式数据,然后执行 dep.notify 进行依赖通知,更新视图

5.Vue.use(plugin) 做了什么? 

  • 首先判断该插件是否已经安装过

  • 如果没有,则执行插件提供的 install 方法安装插件,具体做什么有插件自己决定

6.Vue.mixin(options) 做了什么?(全局混入)

负责在 Vue 的全局配置上合并 options 配置。然后在每个组件生成 vnode 时会将全局配置合并到组件自身的配置上来。

  • 标准化 options 对象上的 props、inject、directive 选项的格式

  • 处理 options 上的 extends 和 mixins,分别将他们合并到全局配置上

  • 然后将 options 配置和全局配置进行合并,选项冲突时 options 配置会覆盖全局配置

7.Vue.component(compName, Comp) 做了什么?(注册全局组件)

负责注册全局组件。其实就是将组件配置注册到全局配置的 components 选项上(options.components),然后各个子组件在生成 vnode 时会将全局的 components 选项合并到局部的 components 配置项上。

  • 如果第二个参数为空,则表示获取 compName 的组件构造函数

  • 如果 Comp 是组件配置对象,则使用 Vue.extend 方法得到组件构造函数,否则直接进行下一步

  • 在全局配置上设置组件信息,this.options.components.compName = CompConstructor

8.Vue 的 nextTick API 是如何实现的? 

因为vue 中更新 DOM 是异步刷新的,而 nextTick 函数是会在下次 DOM 更新后执行

nextTicke 会将传入的函数包装一次 try / catch 然后push 到 callbacks 数组中,然后调用 timerFunc 方法将 flushCallBacks 方法放到 浏览器的异步队列中,当同步任务执行完后,调用异步队列中的函数 ,此时flushCallBacks 方法会将 callBacks 数组遍历 并依次执行 callBacks 数组中的每一个函数

9.vm.$on(event, callback) 做了什么

监听当前实例上的自定义事件,事件可由 vm.$emit 触发,回调函数会接收所有传入事件触发函数(vm.$emit)的额外参数。

vm.$on 的原理很简单,就是处理传递的 event 和 callback 两个参数,将注册的事件和回调函数以键值对的形式存储到 vm._event 对象中,vm._events = { eventName: [cb1, cb2, ...], ... }。

10.vm.$emit(eventName, [...args]) 做了什么?

触发当前实例上的指定事件,附加参数都会传递给事件的回调函数。

其内部原理就是执行 vm._events[eventName] 中所有的回调函数。

11.vm.$off([event, callback]) 做了什么?

移除自定义事件监听器,即移除 vm._events 对象上相关数据。

  • 如果没有提供参数,则移除实例的所有事件监听

  • 如果只提供了 event 参数,则移除实例上该事件的所有监听器

  • 如果两个参数都提供了,则移除实例上该事件对应的监听器

12.runtime-complier 解析过程:

  1. 将template模板转换成抽象语法树(ast);
  2. 通过render函数将抽象语法树转换成虚拟DOM(vdom);
  3. 将虚拟DOM转换成真正的DOM;
  4. template => 抽象语法树(ast) => render() => 虚拟DOM(vdom) => 页面

13.runtime-only 解析过程:

  1. vue-template-compiler插件直接将组件转换成 render函数;
  2. 将render函数返回的虚拟DOM转换成页面;
  3. render() => 虚拟DOM(vdom) => 页面;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值