咱們學JAVA的時候說到繼承就是一個extends ClassName的事情,可是在JS的世界裏繼承和咱們在JAVA所認識的繼承實現方法又有一些不一樣,大家真的瞭解JS的繼承嗎?就當大家很瞭解了,畢竟是基礎知識,我就簡單說說app
簡言之就是把被繼承的對象賦值給繼承者的原型對象函數
function Super() { this.name = 'mirok'; } Super.prototype.showName = function () { console.log(this.name); } function Sub() { this.name = 'july'; } Sub.prototype = new Super(); const obj = new Sub(); obj.showName(); //輸出july
原型實現繼承雖然能夠,可是也有相應的弊端,例如new Super()構建多個實例,繼承裏面的方法被其中一個實例重寫,就會影響其餘實例,也就是說原型裏的是全部實例所共享的,這是咱們不肯看到的,所以就有如下的方法。this
簡言之就是在繼承者的構造函數中去調用被繼承者的構造函數(即便用apply()/call()實現)prototype
function Super() { this.supername = 'mirok'; } function Sub() { Super.call(this) this.name = 'july'; } Sub.prototype = new Super(); const obj = new Sub(); obj.name; //july obj.supername; //mirok
這種方式實現的繼承相對於以前的來講不只解決了以前的問題還能向被繼承者傳參數,可是也有必定的弊端,即容易覆蓋自己的屬性,解決方法就是在調用被繼承者的構造函數再對本身添加屬性,也就是說上面的Super.call要在this.name定義屬性以前。另外一個弊端就是繼承的是沒法共享的code
這個就是組合前面的原型鏈繼承和借用構造函數繼承二者之長,也就是說既能在繼承後的實例都有一份屬性又能共用對象
function Super() { this.name = 'mirok'; } Super.prototype.showName = function () { console.log(this.name); } function Sub1() { Super.call(this); this.name = 'july'; } function Sub2() { Super.call(this); this.name = 'deny'; } Sub1.prototype = new Super(); Sub2.prototype = new Super(); const obj1 = new Sub1(); const obj2 = new Sub2(); obj1.showName(); // july obj2.showName(); // deny
這個比較特殊一點,就是在一個函數裏去作原型鏈繼承的事情繼承
function object(obj) { function fun() {}; fun.prototype = obj; return new fun(); }
ES5規範了這類寫法,就是Object.create(),可是弊端和第一種相似,由於不是咱們理想的繼承這裏就不詳細介紹原型鏈
這個也比較特殊,就是把繼承的事情放在一個函數裏去作,再把對象返回原型
function object(obj) { function fun() {}; fun.prototype = obj; return new fun(); } function factory() { const person = {name:'mirok', age: 22}; const obj = object(person); obj.show = function() {console.log(this.name)} return obj; } factory().show(); //'mirok'
至於弊端可見而知,不能實現共享io
組合繼承有個弊端就是會調用兩次被繼承者的構造函數,解決方法就是使用寄生組合式繼承。這又是什麼呢?這個相對以前的比較複雜,可是高效的一點是隻調用一次被繼承者構造函數,原理就是經過寄生方式建立一個被繼承者的副本,副本和被繼承者共用一個prototype,這樣就解決了以前的問題
function object(obj) { function fun() {}; fun.prototype = obj; return new fun(); } function factory(Sub, Super) { var proto = object(Super.prototype); //返回Super的一個副本 proto.constructer = Sub; //設置constructor指向, 由於新副本的原型對象被重寫 Sub.prototype = proto; //副本做爲sub的原型對象 } function Super () { this.name = 'july'; } Super.prototype.show = function () { console.log(this.name); } function Sub1 () { Super.call(this); this.name = 'mirok' } function Sub2 () { Super.call(this); this.name = 'deny' } factory(Sub1, Super); factory(Sub2, Super); var obj1 = new Sub1(); var obj2 = new Sub2(); obj1.show(); // mirok obj2.show(); // deny