最近流傳各大廠紛紛裁員,導致很多人“被迫”畢業,顯然很多人還是想留級,無奈出現在名單中,只能感嘆命運不公,不過拿了N+1,也算是很欣慰。
又得去面試了,接下來一起來鞏固下vue的3道面試題吧!
computed 實現原理
computed
計算屬性,有兩種定義方式,一種是方法,另一種是 get,set 屬性。並且 computed
監聽的物件必須是已經在 data 定義的屬性
Vue 在建立 computed
屬性時候,會迴圈所有計算屬性,每一個計算屬性會建立一個 watch,並且在通過 defineProperty
監聽,在 get
中,計算屬性工作是做依賴收集,在 set
中,計算屬性重要工作是重新執行計算方法
computed
是懶執行,也就是說第一次初始化之後,不會執行計算,下一次變更執行重新計算是在 set 中
computed
收集時機和 data
一樣,是在元件掛載前,但是其收集物件是自己屬性對應的 watch,而 data 本身所有資料對應一個 watch
具體可以檢視 computed 的實現原始碼,這裡移除服務端渲染相關邏輯
function initComputed(vm: Component, computed: Object) {
const watchers = (vm._computedWatchers = Object.create(null));
for (const key in computed) {
const userDef = computed[key];
const getter = typeof userDef === "function" ? userDef : userDef.get;
if (process.env.NODE_ENV !== "production" && getter == null) {
warn(`Getter is missing for computed property "${key}".`, vm);
}
// 計算屬性獨享watcher
watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions);
// 在例項化Watcher後,開始對計算屬性進行響應式處理
if (!(key in vm)) {
defineComputed(vm, key, userDef);
} else if (process.env.NODE_ENV !== "production") {
if (key in vm.$data) {
warn(`The computed property "${key}" is already defined in data.`, vm);
} else if (vm.$options.props && key in vm.$options.props) {
warn(`The computed property "${key}" is already defined as a prop.`, vm);
}
}
}
}
接下來看 defineComputed
原始碼
if (typeof userDef === "function") {
sharedPropertyDefinition.get = createComputedGetter(key);
sharedPropertyDefinition.set = noop;
} else {
sharedPropertyDefinition.get = userDef.get ? createComputedGetter(key) : noop;
sharedPropertyDefinition.set = userDef.set || noop;
}
Object.defineProperty(target, key, sharedPropertyDefinition);
接下來看 createComputedGetter
函式,獲取計算屬性對應的 watcher
,如果 dirty
是 true
,則計算值,並收集依賴
function createComputedGetter(key) {
return function () {
// 獲取到相應 key 的 computed-watcher
var watcher = this._computedWatchers[key];
// 如果 computed 依賴的資料變化,dirty 會變成true,從而重新計算,然後更新快取值 watcher.value
if (watcher.dirty) {
watcher.evaluate();
}
if (Dep.target) {
watcher.depend();
}
return watcher.value;
};
}
接下來,在 Watcher
類中找到 evaluate
,執行 get
方法,並設定 dirty
為 false
evaluate () {
this.value = this.get()
this.dirty = false
}
get()
方法的定義如下,在這裡執行計算過程,並返回。
Watcher.prototype.get = function () {
// 改變 Dep.target
pushTarget();
// getter 就是 watcher 回撥
var value = this.getter.call(this.vm, this.vm);
// 恢復前一個 watcher
popTarget();
return value;
};
Dep.target = null;
var targetStack = [];
function pushTarget(_target) {
if (Dep.target) {
targetStack.push(Dep.target);
}
Dep.target = _target;
}
function popTarget() {
Dep.target = targetStack.pop();
}
看完了 watcher.evaluate()
接下來看 depend()
方法定義
Watcher.prototype.depend = function () {
var i = this.deps.length;
while (i--) {
dep.addSub(Dep.target);
}
};
這裡看出 watcher
的 deps
儲存的就是 Dep.target
的陣列,沒錯,就是依賴屬性的收集,整個過程就到此完成。
vue-loader 的作用
vue-loader 是 Webpack 的 loader 模組,它使我們可以用 .vue
檔案格式編寫單檔案元件。
單檔案元件檔案有三個部分,即模板(template)、指令碼(script)和樣式(style)。
vue-loader 模組允許 webpack 使用單獨的載入器模組(例如 SASS 或 SCSS 載入器)提取和處理每個部分。該設定使我們可以使用 .vue 檔案無縫編寫程式。
vue-loader 模組還允許把靜態資源視為模組依賴性,並允許使用 webpack 載入器進行處理。而且還允許在開發過程中進行熱重灌。
Vue 外掛的功能
外掛通常用來為 Vue 新增全域性功能。有如下用途
- 新增全域性方法或者 property。如:vue-custom-element
- 新增全域性資源:指令/過濾器/過渡等。如 vue-touch
- 通過全域性混入來新增一些元件選項。如 vue-router
- 新增 Vue 例項方法,通過把它們新增到
Vue.prototype
上實現。 - 一個庫,提供自己的 API,同時提供上面提到的一個或多個功能。如 vue-router
如何自定義 Vue 外掛
Vue.js 的外掛應該暴露一個 install
方法。這個方法的第一個引數是 Vue
構造器,第二個引數是一個可選的選項物件:
MyPlugin.install = function (Vue, options) {
// 1. 新增全域性方法或 property
Vue.myGlobalMethod = function () {
// 邏輯...
}
// 2. 新增全域性資源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 邏輯...
}
...
})
// 3. 注入元件選項
Vue.mixin({
created: function () {
// 邏輯...
}
...
})
// 4. 新增例項方法
Vue.prototype.$myMethod = function (methodOptions) {
// 邏輯...
}
}
寫在最後
如果文中內容對你有幫助, 記得三連~ ??? 如文中有錯誤,也歡迎大家指正修改!
更多前端面經,盡在 www.1024nav.com
禁止轉發