3道常見的vue面試題,你都會了嗎?

HUANGKELEN發表於2022-04-09

最近流傳各大廠紛紛裁員,導致很多人“被迫”畢業,顯然很多人還是想留級,無奈出現在名單中,只能感嘆命運不公,不過拿了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,如果 dirtytrue,則計算值,並收集依賴

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 方法,並設定 dirtyfalse

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);
  }
};

這裡看出 watcherdeps 儲存的就是 Dep.target 的陣列,沒錯,就是依賴屬性的收集,整個過程就到此完成。

vue-loader 的作用

vue-loader 是 Webpack 的 loader 模組,它使我們可以用 .vue 檔案格式編寫單檔案元件。

單檔案元件檔案有三個部分,即模板(template)、指令碼(script)和樣式(style)。

vue-loader 模組允許 webpack 使用單獨的載入器模組(例如 SASS 或 SCSS 載入器)提取和處理每個部分。該設定使我們可以使用 .vue 檔案無縫編寫程式。

vue-loader 模組還允許把靜態資源視為模組依賴性,並允許使用 webpack 載入器進行處理。而且還允許在開發過程中進行熱重灌。

Vue 外掛的功能

外掛通常用來為 Vue 新增全域性功能。有如下用途

  1. 新增全域性方法或者 property。如:vue-custom-element
  2. 新增全域性資源:指令/過濾器/過渡等。如 vue-touch
  3. 通過全域性混入來新增一些元件選項。如 vue-router
  4. 新增 Vue 例項方法,通過把它們新增到 Vue.prototype 上實現。
  5. 一個庫,提供自己的 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

禁止轉發

相關文章