ES5的繼承和ES6的繼承

關于js中的繼承,已經老生常談了,本文將對js的繼承做一個大概的總結.

首先我們可以看一下,es5繼承關系圖,理解繼承的實現,然后再討論不同的繼承的實現方式的問題


ES5的繼承鏈

1.在js實現繼承靠的構造函數的原型對象(即Prototype)

2.js中所有的對象都繼承Object

3.Object的原型對象的[[prototype]]指向null

看完上面的原型繼承圖之后,我們接下來就可以按照原型鏈去實現繼承了


1.組合繼承

function Super(age){

this.name = "lsh";

this.age = age;

}

Super.prototype.sayName = function (){

console.log(this.name);

}

function Sub(){

Super.call(this,99);

}

Sub.prototype = new Super;

Sub.prototype.constructor = Sub;

Sub.prototype.hello = function (){

console.log(this.age);

}

首先借用構造函數,利用的是js中函數執行的環境問題,call和apply可以修改函數執行的函數,實際上是修改了函數內部的this對象.其實就是在子類的構造函數內部調用父類的構造函數,通過call或apply修改其this對象,實現一種繼承的現象.然后再設置子類的prototype為父類的對象,完成原型的繼承

2.原型是繼承

原型繼承要求你必須有一個對象作為另一個對象的基礎,將這個對象傳入Objec.create函數中,create函數返回一個新的對象,這個新的對象的原型就是你傳入的對象.這樣新的對象就會在原型上擁有你傳入對象的所有屬性和方法,包括其原型

function Person(){

this.name = 'lsh';

this.friends = ['name1','name2'];

}

Person.prototype.sayName = function(){

console.log(this.name);

}

var person = new Person();

var person1 = Object.create(person);

person1.friends.push('name3');

var person2 = Object.create(person);

person2.name = 'xindi';

person2.friends.push('name4');

這樣的結果其實就是相當于創造了一個你傳入對象的副本.如果你傳入的對象包含有引用類型的屬性,則這個屬性會被共享.

此時原型鏈的關系就會是

superPerson.__proto__.__proto__ === Person.prototype

superPerson.__proto__.constructor === Person

其實create方法內部的實現機制就是創造了一個臨時的構造函數,然后將臨時構造函數的原型指向你傳入的對象,最后返回臨時構造函數生成的對象.

function create(o){

function F(){};

F.prototype = o;

return new F();

}

所以當你采用原型式繼承的時候,要考慮清楚這種繼承是否滿足你的需要.

3.寄生式繼承

寄生式繼承和原型式繼承關系緊密,其實就是封裝一個繼承用的函數,在函數內部調用原型式繼承,同時在函數內部可以選擇給新的對象增加一個方法或屬性

function createAnother(ori){

let clone = Object.create(ori);

clone.sayHi = function(){

}

return clone;

}

4.寄生組合式繼承

寄生組合式繼承,就是通過構造函數來繼承屬性,通過原型鏈的混成方式來繼承原型的方法或屬性

function inherit(superType,subType){

let prototype = Object.create(superType.prototype);

prototype.constructor = subType;

sub.prototype = prototype;

}

函數第一步創建了一個父類的原型的副本,然后讓這個對象的contructor指向子類的構造函數,最后將子類構造函數的原型設置為這個對象.這樣就實現了一個繼承.

寄生組合式繼承是最理想的繼承方式,推薦使用這個方式.

ps:如何確定實例和原型的關系:

1.instance ?instanceof Super

2.Super.prototype.isPrototypeof instance?

給子類原型添加方法,無論是重寫超類的方法還是添加新的,一定要在原型被替換之后再寫,也就是在調用繼承之后再添加.

不過在ES6 ,js添加了class這個語法糖,其繼承也只需簡單的寫一個extends.

class Super {

? ? ? constructor(name){


? ? ? ? this.name = 'name';


? ? }

? ? ? sayName(){

? ? ? console.log(this.name);

? ? ? }

? ? ? }


class Sub extends Super{

constructor(name){

super(name);

?? ? this.name = 'xindi';

}

}

這個語法糖使得es6的繼承變得無比簡單,不過es6的繼承還是和es5的稍微有點區別,如下圖


es6繼承

es6的繼承相較于es5,其實就多了一個子類構造函數和父類構造函數的關系上,在es5中兩個構造函數沒有任何關系,但是在es6中子類構造函數的__proto__(即[[prototype]])指向了父類的構造函數.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容