詳解JavaScript實(shí)現(xiàn)繼承的五種經(jīng)典方式(附圖解)
前言
- 在 JavaScript 中,實(shí)現(xiàn)繼承的幾種常見(jiàn)方式包括:
- 原型鏈繼承: 此種方式也有兩種方式
- 1.1 共享同一個(gè)父類(lèi)實(shí)例
- 1.2 繞過(guò)父類(lèi)實(shí)例,共享同一個(gè)類(lèi)型原型
- 構(gòu)造函數(shù)繼承(借用構(gòu)造函數(shù))
- 組合繼承
- 原型式繼承
- ES6 類(lèi)繼承
原型鏈繼承
原型鏈繼承-共享同一個(gè)父類(lèi)實(shí)例
這是 JavaScript 最早的繼承方式,通過(guò)將子類(lèi)的原型對(duì)象指向父類(lèi)的實(shí)例,實(shí)現(xiàn)子類(lèi)繼承父類(lèi)的屬性和方法。但它有一個(gè)缺點(diǎn),就是所有子類(lèi)實(shí)例共享同一個(gè)父類(lèi)實(shí)例。
function Parent() {
this.property = "parentProperty";
}
Parent.prototype.say = function () {
console.log("Parent say");
};
function Child() {
this.childProperty = "childProperty";
}
// 修改 Child 的 prototype 屬性指向 Parent 實(shí)例對(duì)象,那么 Child 實(shí)例對(duì)象的 __proto__ 就會(huì)指向其構(gòu)造函數(shù) Child 的 prototype 屬性(即Parent 實(shí)例對(duì)象)
// 修改了 Child.prototype 的指向后,那么原來(lái) Child.prototype 指向的對(duì)象由于被沒(méi)有引用,就會(huì)被回收。
Child.prototype = new Parent();
const childInstance = new Child();
console.log(childInstance.property); // 輸出 'parentProperty'
childInstance.say();下圖是代碼圖解:

上面的代碼看似沒(méi)有問(wèn)題,但其實(shí)還是存在缺陷:
console.log(Child.prototype.constructor); // 輸出:[Function: Parent], 即是 Parent 構(gòu)造函數(shù),這是由于 Child.prototype 自身沒(méi)有,就會(huì)沿著 __proto__ 尋找,因此找到 Parent。這明顯是不對(duì)的 console.log(Child.prototype.constructor === Child); // 輸出:false, 這明顯也是不對(duì)的
因此我們需要再修改 Child.prototype 的指向之后(即代碼 Child.prototype = new Parent(); ),需要同時(shí)修改 Child.prototype.constructor 的指向:
Child.prototype = new Parent(); +Child.prototype.constructor = Child;
- 后續(xù)代碼也是同理!
原型鏈繼承-繞過(guò)父類(lèi)實(shí)例,共享同一個(gè)父類(lèi)的原型
function Parent() {
this.property = "parentProperty";
}
Parent.prototype.say = function () {
console.log("Parent say");
};
function Child() {
Parent.call(this);
this.childProperty = "childProperty";
}
// 方式一:直接指向
// Child.prototype.__proto__ = Parent.prototype;
// 方式二:使用 Object.create(),這是 es5 的方法
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
let childInstance = new Child();
console.log(childInstance.property);
childInstance.say();下圖是代碼圖解:

構(gòu)造函數(shù)繼承(借用構(gòu)造函數(shù))
這種方式通過(guò)在子類(lèi)構(gòu)造函數(shù)中調(diào)用父類(lèi)構(gòu)造函數(shù),實(shí)現(xiàn)繼承屬性。這樣每個(gè)子類(lèi)實(shí)例都擁有獨(dú)立的屬性副本,但無(wú)法繼承父類(lèi)原型上的方法。
function Parent() {
this.property = "parentProperty";
}
Parent.prototype.say = function () {
console.log("Parent say");
};
function Child() {
Parent.call(this);
this.childProperty = "childProperty";
}
const childInstance = new Child();
console.log(childInstance.property); // 輸出 'parentProperty'
// childInstance.say() // 報(bào)錯(cuò):childInstance.say is not a function下圖是代碼圖解:

組合繼承
組合繼承結(jié)合了原型鏈繼承和構(gòu)造函數(shù)繼承,通過(guò)在子類(lèi)構(gòu)造函數(shù)中調(diào)用父類(lèi)構(gòu)造函數(shù),然后設(shè)置子類(lèi)的原型為一個(gè)父類(lèi)實(shí)例,實(shí)現(xiàn)了既能繼承屬性又能繼承方法。
function Parent() {
this.property = "parentProperty";
}
Parent.prototype.say = function () {
console.log("Parent say");
};
function Child() {
Parent.call(this);
this.childProperty = "childProperty";
}
Child.prototype = new Parent();
// 注意:修改其原型對(duì)象之后,同時(shí)必須得修改 constructor 的指向
Child.prototype.constructor = Child;
const childInstance = new Child();
console.log(childInstance.property); // 輸出 'parentProperty'
childInstance.say();
原型式繼承
這種繼承方式創(chuàng)建一個(gè)臨時(shí)的構(gòu)造函數(shù),將這個(gè)構(gòu)造函數(shù)的原型指向父構(gòu)造函數(shù)的原型,再將子構(gòu)造函數(shù)的原型指向該構(gòu)造函數(shù)的實(shí)例,從而實(shí)現(xiàn)繼承。
function mockExtend(Parent, Child) {
function Fn() {}
/**
* 1. 修改了 Fn.prototype 的指向后,那么原來(lái)的 Fn.prototype 沒(méi)有被引用,則會(huì)被回收
* 2. 那么Fn的實(shí)例對(duì)象的 __proto__ 就指向其構(gòu)造函數(shù)的 prototype
*/
Fn.prototype = Parent.prototype;
Child.prototype = new Fn();
// 注意:修改了原型對(duì)象之后,同時(shí)必須得修改 constructor 的指向
Child.prototype.constructor = Child;
}
// =============================== 使用 ==================================
function Parent() {
this.property = "parentProperty";
}
Parent.prototype.say = function () {
console.log("Parent say");
};
function Child() {
Parent.call(this);
this.childProperty = "childProperty";
}
mockExtend(Parent, Child);
const childInstance = new Child();
console.log(childInstance.property);
childInstance.say();下圖是代碼圖解:

ES6 類(lèi)繼承
ES6 引入了 class 關(guān)鍵字,使繼承更加易讀和易用。通過(guò) extends 關(guān)鍵字,一個(gè)類(lèi)可以繼承另一個(gè)類(lèi)的屬性和方法。
class Parent {
constructor() {
this.property = "parentProperty";
}
say() {
console.log("Parent say");
}
}
class Child extends Parent {
constructor() {
super();
this.childProperty = "childProperty";
}
}
const childInstance = new Child();
console.log(childInstance.property); // 輸出 'parentProperty'
childInstance.say();到此這篇關(guān)于詳解JavaScript實(shí)現(xiàn)繼承的五種經(jīng)典方式(附圖解)的文章就介紹到這了,更多相關(guān)JavaScript實(shí)現(xiàn)繼承方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript計(jì)算值然后把值嵌入到html中的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇JavaScript計(jì)算值然后把值嵌入到html中的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
javascript特效實(shí)現(xiàn)——當(dāng)前時(shí)間和倒計(jì)時(shí)效果的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇javascript特效實(shí)現(xiàn)——當(dāng)前時(shí)間和倒計(jì)時(shí)效果的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07
琥珀無(wú)限級(jí)聯(lián)動(dòng)菜單-JavaScript版
琥珀無(wú)限級(jí)聯(lián)動(dòng)菜單-JavaScript版...2006-11-11
將JSON字符串轉(zhuǎn)換成Map對(duì)象的方法
下面小編就為大家?guī)?lái)一篇將JSON字符串轉(zhuǎn)換成Map對(duì)象的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11
關(guān)于Javascript 對(duì)象(object)的prototype
Javascript中的每個(gè)對(duì)象(object)都會(huì)有 prototype,下面為大家介紹下其具體的應(yīng)用2014-05-05
利用JS動(dòng)態(tài)生成隔行換色HTML表格的兩種方法
這篇文章主要介紹了利用JS動(dòng)態(tài)生成隔行換色HTML表格的兩種方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10
JS+HTML5 Canvas實(shí)現(xiàn)簡(jiǎn)單的寫(xiě)字板功能示例
這篇文章主要介紹了JS+HTML5 Canvas實(shí)現(xiàn)簡(jiǎn)單的寫(xiě)字板功能,結(jié)合實(shí)例形式分析了js結(jié)合HTML5 canvas特性的圖形繪制相關(guān)操作技巧,需要的朋友可以參考下2018-08-08
用JS實(shí)現(xiàn)的一個(gè)include函數(shù)
用JS實(shí)現(xiàn)的一個(gè)include函數(shù)...2007-07-07
利用Promise自定義一個(gè)GET請(qǐng)求的函數(shù)示例代碼
這篇文章主要給大家介紹了關(guān)于如何利用Promise自定義一個(gè)GET請(qǐng)求的函數(shù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Promise具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03

