ES5的繼承和ES6的繼承

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

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


ES5的繼承鏈

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

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

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

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


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);

}

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

2.原型是繼承

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

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');

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

此時原型鏈的關系就會是

superPerson.__proto__.__proto__ === Person.prototype

superPerson.__proto__.constructor === Person

其實create方法內(nèi)部的實現(xiàn)機制就是創(chuàng)造了一個臨時的構造函數(shù),然后將臨時構造函數(shù)的原型指向你傳入的對象,最后返回臨時構造函數(shù)生成的對象.

function create(o){

function F(){};

F.prototype = o;

return new F();

}

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

3.寄生式繼承

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

function createAnother(ori){

let clone = Object.create(ori);

clone.sayHi = function(){

}

return clone;

}

4.寄生組合式繼承

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

function inherit(superType,subType){

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

prototype.constructor = subType;

sub.prototype = prototype;

}

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

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

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

1.instance ?instanceof Super

2.Super.prototype.isPrototypeof instance?

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

不過在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的稍微有點區(qū)別,如下圖


es6繼承

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

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容