當回答面試官問及的Vue問題,咱們除了照本宣科的回答外,其實還能夠根據少許的源碼來秀一把,來體現出你對Vue的深度瞭解。前端
本文會陸續更新,這次涉及如下問題:vue
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) } } } 複製代碼
initProxy
,做用域代理,攔截組件內訪問其它組件的數據。initLifecycle
, 創建父子組件關係,在當前實例上添加一些屬性和生命週期標識。如:$children
、$refs
、_isMounted
等。initEvents
,用來存放除@hook:生命週期鉤子名稱="綁定的函數"
事件的對象。如:$on
、$emit
等。initRender
,用於初始化$slots
、$attrs
、$listeners
initInjections
,初始化inject
,通常用於更深層次的組件通訊,至關於增強版的props
。用於組件庫開發較多。只要在上一層級的聲明的provide,那麼下一層級不管多深都可以經過inject來訪問到provide的數據。這麼作也是有明顯的缺點:在任意層級都能訪問,致使數據追蹤比較困難,不知道是哪個層級聲明瞭這個或者不知道哪一層級或若干個層級使用。vue-cli
initState
,是不少選項初始化的彙總,包括:props、methods、data、computed 和 watch
等。initProvide
,初始化provide
。vm.$mount
,掛載實例。這個回答能夠從beforeCreate
以及 created
的調用時機談起,咱們根據上面的概述,來簡化下代碼:api
callHook(vm, 'beforeCreate') // 初始化 inject // 初始化 props、methods、data、computed 和 watch // 初始化 provide callHook(vm, 'created') // 掛載實例 vm.$mount(vm.$options.el) 複製代碼
因此當面試官問你:數組
beforeCreate
以及 created
調用時,哪些數據能用與否?created
以後才掛載實例?知道怎麼回答了吧。瀏覽器
常規回答這裏就不說了,來稍微深刻點的:緩存
created/mounted/updated/destroyed
,以及對應的before
鉤子。分別是建立=>掛載=>更新=>銷燬。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
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.10
的變化,嘖嘖...面試官確定更加欣賞你。拿callHook(vm, 'created')
講,先判斷組件的選項中有無對應名字的生命週期鉤子,再判斷是否有 parentVal(vm)
。若存在parentVal(vm)
且都有對應的生命週期鉤子,則會將二者concat
爲一個數組(parentVal.concat(childVal
))。因此,生命週期鉤子實際上是能夠寫成數組。如:
created: [ function () { console.log('first') }, function () { console.log('second') }, function () { console.log('third') }] 複製代碼
鉤子函數將按順序執行。
三種 "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}`) } } 複製代碼
類型: 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
,路由會自動強制進入這個模式.keep-alive
的瞭解?」先貼一個常規回答:
keep-alive是 Vue 內置的一個組件,可使被包含的組件保留狀態,或避免從新渲染。 在vue 2.1.0 版本以後,keep-alive新加入了兩個屬性: include(包含的組件緩存) 與 exclude(排除的組件不緩存,優先級大於include) 。
而後你能夠開始騷了:
<keep-alive>
是 Vue
源碼中實現的一個全局抽象組件,經過自定義 render
函數而且利用了插槽來實現數據緩存和更新。它的定義在src/core/components/keep-alive.js
中:export default { name: 'keep-alive', abstract: true, ... } 複製代碼
abstract
選項來聲明的。抽象組件不渲染真實DOM
,且不會出如今父子關係的路徑上(initLifecycle
會忽略抽象組件),相關代碼片斷:if (parent && !options.abstract) { // abstract 即 `ptions.abstract` // while 循環查找第一個非抽象的父組件 while (parent.$options.abstract && parent.$parent) { parent = parent.$parent } parent.$children.push(vm) } 複製代碼
Vue2.6+
新全局API
:Vue.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 } 複製代碼
再看看它import
的observe
,最近一次提交在12/1/2018
,唔。。。。
observe(obj)
觀測後的數據,代碼啥都沒改。懂了吧?
目前本人在準備跳槽,但願各位大佬和HR小姐姐能夠內推一份靠譜的深圳前端崗位!
huab119
454274033@qq.com