Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >「从源码中学习」面试官都不知道的Vue题目答案

「从源码中学习」面试官都不知道的Vue题目答案

作者头像
前端劝退师
发布于 2019-09-17 07:11:02
发布于 2019-09-17 07:11:02
51700
代码可运行
举报
文章被收录于专栏:前端劝退师前端劝退师
运行总次数:0
代码可运行

前言

当回答面试官问及的Vue问题,我们除了照本宣科的回答外,其实还可以根据少量的源码来秀一把,来体现出你对Vue的深度了解。

本文会陆续更新,此次涉及以下问题:

  1. “new Vue()做了什么?”
  2. “什么阶段才能访问DOM?”
  3. “谈谈你对Vue生命周期的理解。”
  4. 扩展:新生命周期钩子serverPrefetch是什么?
  5. “vue-router路由模式有几种?”
  6. “谈谈你对keep-alive的了解?”
  7. “了解Vue2.6+新全局API:Vue.observable()吗?”

1. “ newVue()做了什么?”

new关键字代表实例化一个对象, 而 Vue实际上是一个类, 源码位置是 /src/core/instance/index.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

接着我们跳转追踪至 this._init(),即 Vue.prototype._init,位于 src\core\instance\init.js_init()方法的内部有一系列 init* 的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // ...忽略,从第45行看起
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
    // ...忽略
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}

1.1 这里我们概述一遍:

  1. initProxy,作用域代理,拦截组件内访问其它组件的数据。
  2. initLifecycle, 建立父子组件关系,在当前实例上添加一些属性和生命周期标识。如: $children$refs_isMounted等。
  3. initEvents,用来存放除 @hook:生命周期钩子名称="绑定的函数"事件的对象。如: $on$emit等。
  4. initRender,用于初始化 $slots$attrs$listeners
  5. initInjections,初始化 inject,一般用于更深层次的组件通信,相当于加强版子组件的 props。用于组件库开发较多。

只要在上一层级的声明的provide,那么下一层级无论多深都能够通过inject来访问到provide的数据。这么做也是有明显的缺点:在任意层级都能访问,导致数据追踪比较困难,不知道是哪一个层级声明了这个或者不知道哪一层级或若干个层级使用。

  • initState,是很多选项初始化的汇总,包括: props、methods、data、computed和watch 等。
  • initProvide,初始化 provide
  • vm.$mount,挂载实例。

2. “什么阶段才能访问DOM?”

这个回答可以从 beforeCreate以及 created 的调用时机谈起,我们根据上面的概述,来简化下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
callHook(vm, 'beforeCreate')
// 初始化 inject
// 初始化 props、methods、data、computed 和 watch
// 初始化 provide
callHook(vm, 'created')
// 挂载实例 vm.$mount(vm.$options.el)

所以当面试官问你:

  • beforeCreate以及 created 调用时,哪些数据能用与否?
  • 什么阶段才能访问DOM?
  • 为什么 created之后才挂载实例?

知道怎么回答了吧。

3. “谈谈你对Vue的生命周期的理解”

常规回答这里就不说了,来稍微深入点的:

  1. created/mounted/updated/destroyed,以及对应的 before钩子。分别是创建=>挂载=>更新=>销毁。
  2. Vue源码中定义了一个 mergeHook函数来遍历一个常量数组 LIFECYCLE_HOOKS,该数组实际上是由与生命周期钩子同名的字符串组成的数组。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// v2.6.10 最新版
var LIFECYCLE_HOOKS = [
    'beforeCreate',
    'created',
    'beforeMount',
    'mounted',
    'beforeUpdate',
    'updated',
    'beforeDestroy',
    'destroyed',
    'activated',
    'deactivated',
    'errorCaptured',
    // v2.6+ 
    'serverPrefetch'
];

于是,你可以答多 activated&deactivated(keep-alive 组件激活/停用)、errorCaptured(v2.5 以上版本有的一个钩子,用于处理错误)这三个。

3.1 新生命周期钩子: serverPrefetch是什么?

可以看到, serverPrefetch前身是 ssrPrefetch。顾名思义,这是用来处理ssr的。允许我们在渲染过程中“等待”异步数据。可在任何组件中使用,而不仅仅是路由组件。

这里我们贴出一段官方例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!-- Item.vue -->
<template>
  <div v-if="item">{{ item.title }}</div>
  <div v-else>...</div>
</template>

<script>
export default {
  computed: {
    item () {
      return this.$store.state.items[this.$route.params.id]
    }
  },
  serverPrefetch () {
    return this.fetchItem()
  },
  mounted () {
    if (!this.item) {
      this.fetchItem()
    }
  },
  methods: {
    fetchItem () {
      // return the Promise from the action
      return this.$store.dispatch('fetchItem', this.$route.params.id)
    }
  }
}
</script>
  • 绝大多数的面试官都不会去关注v2.6+ 以后的代码记录和变更。这里如果你说出这个 v2.6.10的变化,啧啧...面试官肯定更加欣赏你。

3.2 生命周期钩子的合并策略

callHook(vm,'created')讲,先判断组件的选项中有无对应名字的生命周期钩子,再判断是否有 parentVal(vm)。若存在 parentVal(vm)且都有对应的生命周期钩子,则会将两者 concat为一个数组( parentVal.concat(childVal))。所以,生命周期钩子其实是可以写成数组。如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
created: [
function () {
  console.log('first')
},
function () {
  console.log('second')
},
function () {
  console.log('third')
}]

钩子函数将按顺序执行。

4. “Vue-router 路由模式有几种?”

三种 "hash"|"history"|"abstract",一般人只知道两种 "hash"|"history"

这里贴出源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
switch (mode) {
  case 'history':
    this.history = new HTML5History(this, options.base)
    break
  case 'hash':
    this.history = new HashHistory(this, options.base, this.fallback)
    break
  case 'abstract':
    this.history = new AbstractHistory(this, options.base)
    break
  default:
    if (process.env.NODE_ENV !== 'production') {
      assert(false, `invalid mode: ${mode}`)
    }
}
# mode

类型: string

默认值: "hash"(浏览器环境)|"abstract"(Node.js环境)

可选值: "hash"|"history"|"abstract" 配置路由模式:

  • hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5HistoryApi 的浏览器。
  • history: 依赖 HTML5History API 和服务器配置。查看 HTML5History 模式。
  • abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.

5. “谈谈你对 keep-alive的了解?”

先贴一个常规回答:

keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。 在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。

然后你可以开始骚了:

  1. <keep-alive>Vue 源码中实现的一个全局抽象组件,通过自定义 render 函数并且利用了插槽来实现数据缓存和更新。它的定义在 src/core/components/keep-alive.js 中:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default {
  name: 'keep-alive',
  abstract: true,
  ...
}
  1. 所有的抽象组件是通过定义 abstract选项来声明的。抽象组件不渲染真实 DOM,且不会出现在父子关系的路径上( initLifecycle会忽略抽象组件),相关代码片段:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (parent && !options.abstract) {
  // abstract 即 `ptions.abstract`
  // while 循环查找第一个非抽象的父组件
  while (parent.$options.abstract && parent.$parent) {
    parent = parent.$parent
  }
  parent.$children.push(vm)
}

6. “了解 Vue2.6+新全局 APIVue.observable()吗?”

Vue2.6+新的全局API是 Vue.observable(),它的使用方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import vue from vue;
const state = Vue.observable ({
   counter: 0,
});
export default {
   render () {
     return (
       <div>
         {state.counter}
           <button v-on:click={() => {state.counter ++; }}>
           Increment counter
         </ button>
       </ div>
     );
   },
};

而它定义在 /src/core/global-api/index.js第48行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { observe } from 'core/observer/index'
// ...
// 2.6 explicit observable API
Vue.observable = <T>(obj: T): T => {
observe(obj)
return obj
}

再看看它 importobserve,最近一次提交在 12/1/2018,唔。。。。

核心就是暴露出 observe(obj)观测后的数据,代码啥都没改。懂了吧?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端劝退师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
高级前端开发者必会的34道Vue面试题解析(四)
在生命周期的每个节点,Vue提供了一些钩子函数,使得开发者的代码能被有机会执行。这里的钩子函数可以简单理解为,在Vue实例中预先定义了一些像created,mounted等特定名称的函数,函数体的内容开发给开发者填充,当被实例化的时候,会按照确定的先后顺序来执行这些钩子函数,从而将开发者的代码有机会执行。
用户1462769
2020/04/10
1.4K1
高级前端开发者必会的34道Vue面试题解析(四)
从源码解读Vue生命周期,让面试官对你刮目相看
在我们的实际项目中,与Vue的生命周期打交道可以说是家常便饭。掌握Vue的生命周期对开发者来说是特别重要的。那么如果能够从源码角度理解Vue的生命周期,对我们的开发和成长会有进一步的提升。
童欧巴
2020/03/30
5980
从源码解读Vue生命周期,让面试官对你刮目相看
常考vue面试题(附答案)
当一个Vue实例创建时,Vue会遍历data中的属性,用 Object.defineProperty(vue3.0使用proxy )将它们转为 getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。
bb_xiaxia1998
2022/12/14
7400
2023前端二面必会vue面试题指南4
早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 '#search'
bb_xiaxia1998
2023/01/06
6640
vue高频面试题合集(四)附答案
使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是还是有必要让解决这个问题的。
helloworld1024
2022/08/12
7890
如何准备vue相关的知识点
如果需要在组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件。
bb_xiaxia1998
2022/09/26
6960
彻底揭秘keep-alive原理
用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。 总的来说,keep-alive用于保存组件的渲染状态。
前端黑板报
2020/03/26
1.9K0
彻底揭秘keep-alive原理
vue-router 源码阅读 - 文件结构与注册机制
前端路由是我们前端开发日常开发中经常碰到的概念,在下在日常使用中知其然也好奇着所以然,因此对 vue-router 的源码进行了一些阅读,也汲取了社区的一些文章优秀的思想,于本文记录总结作为自己思考的输出,本人水平有限,欢迎留言讨论~
前端下午茶
2019/06/27
9380
vue-router 源码阅读 - 文件结构与注册机制
vue源码分析-从new Vue开始
那你觉得是不是很有意思,咱们new Vue之后,就可以使用他那么多的功能,可见Vue是暴出来的一个一个功能类函数,我们进入源码一探究竟:
yyzzabc123
2022/10/19
6320
【Vuejs】887- 深入浅出 Vue Mixin
https://flyyang.me/2019/01/24/vue-mixin/
pingan8787
2021/03/16
4710
【Vuejs】887- 深入浅出 Vue Mixin
30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)
本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性、框架的原理以问题的形式进行整理汇总,意在帮助作者及读者自测下 Vue 掌握的程度。本文章节结构以从易到难进行组织,建议读者按章节顺序进行阅读,当然大佬级别的请随意。希望读者读完本文,有一定的启发思考,也能对自己的 Vue 掌握程度有一定的认识,对缺漏之处进行弥补,对 Vue 有更好的掌握。文章最后一题,欢迎同学们积极回答,分享各自的经验 ~~~
Nealyang
2019/09/29
1.7K0
30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)
浅析 vue-router 源码和动态路由权限分配
? 这是第 72 篇不掺水的原创,想要了解更多,请戳上方蓝色字体:政采云前端团队 关注我们吧~ 本文首发于政采云前端团队博客:浅析 vue-router 源码和动态路由权限分配 https://ww
政采云前端团队
2020/10/26
4.7K0
浅析 vue-router 源码和动态路由权限分配
哪些vue面试题是经常会被问到的
vue-loader会调用@vue/compiler-sfc模块解析SFC源码为一个描述符(Descriptor),然后为每个语言块生成import代码,返回的代码类似下面
bb_xiaxia1998
2022/09/25
1.1K0
Vue——Vue初始化【三】
今天我们来解密下init.ts中的代码内容,并结合 vue 生命周期来分析下 vue 的初始化;
思索
2024/08/15
1660
Vue——Vue初始化【三】
前端经典面试题解密:Vue 的生命周期到底做了什么事清?(源码详解)
相信大家对 Vue 有哪些生命周期早就已经烂熟于心,但是对于这些生命周期的前后分别做了哪些事情,可能还有些不熟悉。
胡哥有话说
2020/04/14
1.2K0
30 道 Vue 面试题,内含详细讲解(中)
比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,可以通过以下写法实现:
公号:咻咻ing
2019/09/10
1.3K0
vue-生命周期 源码
生命周期的过程就是vue实例从创建到销毁的过程。在这个过程中提供了一些钩子函数用于让用户自定义一些方法。
用户3258338
2019/10/08
4650
vue mixins原理
以前一直以为mixins在vue里面应该不是很重要,只是提供了一个混入的api,慢慢的才知道mixin在vue里面非常重要。生命周期、vuex等都有mixin的影子,在内部算是很重要的一个api。
wade
2020/09/14
5110
必会vue面试题(附答案)
使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是还是有必要让解决这个问题的。
bb_xiaxia1998
2022/12/19
1.3K0
【源码学习】Vue 初始化过程 (附思维导图)
---- 声明 🔊 本文是开始学习 Vue 源码的第二篇笔记,当前的版本是 2.6.14 。如果对你有一点点帮助,请点赞鼓励一下,如果有错误或者遗漏,请在评论区指出,非常感谢各位大佬。 🔊 代码基本上是逐行注释,由于本人的能力有限,很多基础知识也进行了注释和讲解。由于源码过长,文章不会贴出完整代码,所以基本上都是贴出部分伪代码然后进行分析。 🔊 从本篇文章开始,可能会出现暂时看不懂的地方,是因为还没有学习前置知识,不必惊慌,只需知道存在这样一个知识点,接着向下看,看完了前置知识,回过头来再看这里就一目了
一尾流莺
2022/12/10
1.1K0
【源码学习】Vue 初始化过程 (附思维导图)
推荐阅读
相关推荐
高级前端开发者必会的34道Vue面试题解析(四)
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验