主要分爲兩部分,第一部分是ES5環境下的繼承,另一部分是ES6部分的繼承,首先先看ES5,如何經過構造函數的形式實現繼承。
1:原型鏈繼承
function Foo(name) { this.name = name; } Foo.prototype.age = function() { console.log('父類:' + this.name); }; function fn (name) { this.name = name; } fn.prototype = new fn(); fn.prototype.age = function() { console.log('子類:' + this.name); }; var a = new fn('lisi'); a.age();
這種方法缺點比較明顯,看起來很不直觀,並且子類的方法不能優先於父類方法出現,經過new調用時,不能直接調用父類的構造函數而是要調用子類。函數
2:類式繼承
function Foo(name) { this.name = name; } Foo.prototype.age = function() { console.log('父類:' + this.name); }; Foo.prototype.obj = function() { console.log('hello world'); }; function fn (name) { Foo.call(this,name); } fn.prototype.age = function() { console.log('子類:' + this.name); }; var a = new fn('lisi'); a.age(); a.obj(); //TypeError: a.obj is not a function
這裏經過call的方法,將this綁定在Foo構造函數上運行,可是會致使沒有本身的原型對象,沒法共享原型的方法和屬性。
3:組合式繼承
function Foo(name) { this.name = name; } Foo.prototype.age = function() { console.log('父類:' + this.name); }; Foo.prototype.obj = function() { console.log('hello world'); }; function fn (name) { Foo.call(this,name); //第二次調用
} fn.prototype = new Foo(); //第一次調用
fn.prototype.constructor = fn; fn.prototype.age = function() { console.log('子類:' + this.name); }; fn.prototype.set = function() { console.log('set si es5'); }; var a = new fn('lisi'); a.age(); a.obj(); a.set();
這是比較經常使用的繼承方法,經過調用兩次實現了繼承,具有了原型鏈繼承和類式繼承的優勢也能夠本身定製方法或者屬性。
不過缺點就是第一次調用Foo函數,實際上咱們只是想獲取原型,你可能在想若是經過
fn.prototype = Foo.prototype;
的方法實現,不過很惋惜,這種方法是錯誤的,由於這會致使,兩個函數的prototype屬性發生改變,這顯然是沒有必要的。
這也是第四種繼承的由來。
4:寄生組合式繼承
function Foo(name) { this.name = name; } Foo.prototype.age = function() { console.log('父類:' + this.name); }; Foo.prototype.obj = function() { console.log('hello world'); }; function fn (name) { Foo.call(this,name); } fn.prototype = Object.create(Foo.prototype); fn.prototype.constructor = fn; fn.prototype.age = function() { console.log('子類:' + this.name); }; fn.prototype.set = function() { console.log('set si es5'); }; var a = new fn('lisi'); a.age(); a.obj(); a.set();
這裏使用了Object.create()方法,事實上你也能夠經過這種方法本身模擬一個,使用這種方法繼承,能夠讓Foo這個函數只執行一次。
function Create(arr) { function foo() {} foo.prototype = arr; return new foo(); }
5:多重繼承(混合繼承)
function foo(name) { this.name = name; } function fn(arr) { this.age = arr; } function obj(name, age) { foo.call(this, name); fn.call(this, age); } obj.prototype = Object.create(foo.prototype); Object.assign(obj.prototype, fn.prototype); obj.prototype.constructor = obj; var a = new obj('zhangsan', 18); console.log(a); //obj {name: "zhangsan", age: 18}
class繼承
class是ES6新增的,繼承經過extends實現
class Foo { constructor(name) { this.name = name; } age() { console.log(this.name); } obj() { console.log('hello world'); } } class fn extends Foo { constructor(name) { super(name); } age() { console.log(`子類調用${this.name}`); } } var a = new fn('zhangsan'); a.age(); a.obj();
參考文章:
30分鐘學會js繼承