「從源碼中學習」面試官都不知道的Vue題目答案

前言

當回答面試官問及的Vue問題,咱們除了照本宣科的回答外,其實還能夠根據少許的源碼來秀一把,來體現出你對Vue的深度瞭解。前端

本文會陸續更新,這次涉及如下問題:vue

  1. 「new Vue()作了什麼?」
  2. 「什麼階段才能訪問DOM?」
  3. 「談談你對Vue生命週期的理解。」
  4. 擴展:新生命週期鉤子serverPrefetch是什麼?
  5. 「vue-router路由模式有幾種?」
  6. 「談談你對keep-alive的瞭解?」
  7. 「瞭解Vue2.6+新全局API:Vue.observable()嗎?」

1. 「new Vue()作了什麼?」

new關鍵字表明實例化一個對象, 而Vue其實是一個類, 源碼位置是/src/core/instance/index.js面試

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* 的方法vue-router

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的數據。這麼作也是有明顯的缺點:在任意層級都能訪問,致使數據追蹤比較困難,不知道是哪個層級聲明瞭這個或者不知道哪一層級或若干個層級使用。vue-cli

  • initState,是不少選項初始化的彙總,包括:props、methods、data、computed 和 watch 等。
  • initProvide,初始化provide
  • vm.$mount,掛載實例。

2. 「什麼階段才能訪問DOM?」

這個回答能夠從beforeCreate以及 created 的調用時機談起,咱們根據上面的概述,來簡化下代碼:api

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,該數組其實是由與生命週期鉤子同名的字符串組成的數組。
// 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 以上版本有的一個鉤子,用於處理錯誤)這三個。bash

3.1 新生命週期鉤子:serverPrefetch是什麼?

能夠看到,serverPrefetch前身是ssrPrefetch。顧名思義,這是用來處理ssr的。容許咱們在渲染過程當中「等待」異步數據。可在任何組件中使用,而不只僅是路由組件。

這裏咱們貼出一段官方例子:

<!-- 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))。因此,生命週期鉤子實際上是能夠寫成數組。如:

created: [
function () {
  console.log('first')
},
function () {
  console.log('second')
},
function () {
  console.log('third')
}]
複製代碼

鉤子函數將按順序執行。

4. 「Vue-router 路由模式有幾種?」

三種 "hash" | "history" | "abstract",通常人只知道兩種"hash" | "history"

這裏貼出源碼:

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 值來做路由。支持全部瀏覽器,包括不支持 HTML5 History Api 的瀏覽器。
  • history: 依賴 HTML5 History API 和服務器配置。查看 HTML5 History 模式。
  • 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 中:
export default {
  name: 'keep-alive',
  abstract: true,
  ...
}
複製代碼
  1. 全部的抽象組件是經過定義abstract選項來聲明的。抽象組件不渲染真實DOM,且不會出如今父子關係的路徑上(initLifecycle會忽略抽象組件),相關代碼片斷:
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(),它的使用方式:

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行:

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)觀測後的數據,代碼啥都沒改。懂了吧?

求一份深圳的內推

目前本人在準備跳槽,但願各位大佬和HR小姐姐能夠內推一份靠譜的深圳前端崗位!

  • 微信:huab119
  • 郵箱:454274033@qq.com

做者掘金文章總集

公衆號:

相關文章
相關標籤/搜索