es5繼承和es6繼承中靜態方法、靜態屬性的差別

最近在看vue的源碼,其中有一部分牽扯到了繼承,看到es5中靜態方法的"繼承"是這樣寫的vue

const Sub = function VueComponent (options) {
        this._init(options)
      }
      Sub.prototype = Object.create(Super.prototype)
      Sub.prototype.constructor = Sub
        ...
      Sub.extend = Super.extend
      Sub.mixin = Super.mixin
      Sub.use = Super.use
複製代碼

es5的繼承你們都知道(經過原型鏈實現原型屬性的繼承,經過構造函數實現實例屬性的繼承),但代碼中靜態方法是直接從父類賦給子類的,這就想到的一個問題?靜態方法沒有繼承嗎?帶着這個問題研究了一下靜態方法在es5繼承中和es6繼承中的差別es6

es5中靜態方法的繼承

// 定義父類
    function Super(name, age) {
      this.name = name;
      this.age = age;
    };
    Super.prototype.sayName = function() {
      return this.name;
    };
    // 定義屬性
    Super.num = 1;
    // 定義靜態方法
    Super.sayWord = function(word) {
      return word;
    };
    // 定義子類
    function Sub(name, age, sex) {
      // 繼承實例屬性
      Super.call(this, name, age);
      this.sex = sex;
    }
    // 繼承父類的原型方法+原型屬性
    Sub.prototype = Object.create(Super.prototype);
    Sub.prototype.constructor = Sub;
    
    var instance = new Sub('張三', '18', '男');
複製代碼

分別打印出來看下結果:函數

console.log(Super.sayWord('hello world'));
    // print TypeError: Sub.sayWord is not a function
    
    console.log(Sub.sayWord('hello world'));
   // print TypeError: Sub.sayWord is not a function
    
    console.log(instance.sayWord('hello world'));  // 實例是沒法獲取到靜態方法的
    // print instance.sayWord is not a function
複製代碼

靜態屬性和靜態方法相似,你們能夠自行驗證,經過上面的咱們能夠得出下面的結論: es5的類繼承:子類是沒法繼承父類的靜態屬性和靜態方法的,只是經過傳遞測試

其中有個須要注意的地方:靜態方法沒辦法獲取到this,因爲JavaScript中的類也是一個對象,靜態方法至關因而這個類對象的一個屬性方法,可是this指的是當前實例對象而不是類對象,因此是沒法取到的,下面看下es6中的ui

es6中靜態方法的繼承

class Super {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayName() {
    return this.name;
  }

  static sayWord(word) {
    return word;
  }

  static get num() {
    return this._num; // 由於類也是一個對象 因此_num 只是這個類上的屬性 並不是實例屬性
  }

  static set num(n) {
    this._num = n;
  }
}

class Sub extends Super {
  constructor(name, age, sex) {
    super(name, age);
    this.sex = sex;
  }
}

const instance = new Sub('張三', '18', '男');
複製代碼

下面咱們分別看下靜態方法和靜態屬性this

console.log(Super.sayWord('hello world'));
// print hello world
console.log(Sub.sayWord('hello world'));
// print hello world
console.log(instance.sayWord('hello world'));
// print TypeError: instance.sayWord is not a function
複製代碼

能夠看出es6繼承中,靜態方法被繼承下來,這點與es5仍是有差別的,再看靜態屬性, es6中的靜態屬性能夠直接[類名].[屬性名]這樣的定義,也能夠如上面那樣定義(get,set),只是get,set這樣的定義咱們能夠更好進行的控制es5

Super.num = 3;
console.log(Super.num);
// print 3
console.log(Sub.num);
// print 3
複製代碼

看的出,靜態屬性也被繼承了,可是這樣也有問題,當靜態屬性是引用類型時,子類和父類指向的同一個地址,父類若是發生變化子類也會跟着變化,這是咱們不但願看到的spa

Super.num = [];

Sub.num.push(1);
console.log(Super.num);
// print [1]
console.log(Sub.num);
// print [1]

Super.num.push(2);
console.log(Super.num);
// print [1,2]
console.log(Sub.num);
// print [1,2]
複製代碼

咱們修改下靜態屬性num的get方法,使其只獲取本身當前類的值,而非繼承的值prototype

static get num() {
    return this.hasOwnProperty('_num') ? this._num : undefined;
  }
複製代碼

再測試一下:code

Super.num = [];
// Sub.num.push(1);
// print TypeError: Cannot read property 'push' of undefined 由於Sub.num獲得的是 undefined
Sub.num=1;
console.log(Super.num);
// print []
console.log(Sub.num);
// print 1
Super.num.push(2);
console.log(Super.num);
// print [2]
console.log(Sub.num);
// print 1
複製代碼

能夠得出:es6中的靜態方法和靜態屬性均可以被繼承下來的,只是靜態屬性的繼承須要稍做處理,不然就被共享了

下面咱們再總結下:

  1. es5和es6實現繼承的方式是不一樣的,前者經過原型鏈實現對父類原型方法、原型屬性的繼承,經過構造函數的調用實現對實例方法,實例屬性的調用,後者經過extends關鍵字實現繼承
  2. es5中靜態方法、靜態屬性是沒法經過繼承下來的,只能經過賦值傳遞,如最開始的demo,但es6中則是能夠的
相關文章
相關標籤/搜索