1. 程式人生 > >原型繼承問題迷失

原型繼承問題迷失

enume 它的 判斷 lean 經驗 明顯 開發 tor new

問題描述

在開發中需要實現一個自定義Error,它繼承自Error,按照經驗,一般會這樣來做:

function CustomError(message) {
  this.message = message;
}

CustomError.prototype = Object.create(Error.prototype, {
  name: {
    value: ‘customError‘
  },
  constructor: {
    value: Error,
    enumerable: false,
    writable: true,
    configurable: true
  }
});

var myError = new CustomError(‘f**k error!‘);

console.log(myError instanceof CustomError) // true
console.log(myError instanceof Error) // true

它工作的很好,沒有明顯的bug,所以長期以來,我都這麽幹。直到某天試著這樣:

> console.log(CustomError instanceof Error)
< false

為什麽這裏返回的是false?認真思考,等下給出答案。

再一個,回到題目本身,我想和大家討論的是函數之間的繼承關系。具體而言,就是CustomError通過原型鏈繼承於Error,實現預期不僅表現在CustomError的每一個實例上,也表現在其本身——CustomError instanceof Error === true

解決之道

要解答上面的問題,必須清楚這裏的instanceof操作,就是判斷CustomError

的原型鏈(proto)上是否存在Error.prototype,返回一個Boolean。

所以結果false並不令人感到奇怪,因為沒有任何跡象表明CustomError.__proto__指向Error.prototype

上面這句話暗含了解決之道:

> CustomError.__proto__ = Error.prototype
> CustomError instanceof Error
< true

延展

  • 原型(prototype)
    每個函數有一個prototype屬性,它的值是一個對象(屬性的集合),默認只有一個constructor屬性。
  • 原型鏈(proto)
    1、每個對象
    默認有一個__proto__屬性,指向創建該對象的函數的prototype。
    2、函數也是對象,也默認有一個__proto__屬性,指向Function.prototype。
    3、訪問一個對象的屬性時,先在該對象的基本屬性中查找,如果沒有,在沿著__proto__這條鏈向上查找,這就是原型鏈。
  • instanceof 運算符
    用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。
  • Object.create()
    使用指定的原型對象及其屬性去創建一個新的對象(依然維持著對原型對象的引用)。

原型繼承問題迷失