最近在看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
// 定義父類
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
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中的靜態方法和靜態屬性均可以被繼承下來的,只是靜態屬性的繼承須要稍做處理,不然就被共享了
下面咱們再總結下: