JavaScript類的繼承全面示例講解
1. ES5 中的繼承
首先假設(shè)我們有一個(gè)父類 Person
,并且在類的內(nèi)部和原型鏈上各定義了一個(gè)方法:
function Person(name, age) { this.name = name; this.age = age; this.greed = function() { console.log('Hello, I am ', this.name); } } Person.prototype.getInfo = function() { return this.name + ',' + this.age; }
1.1 修改原型鏈
這是最普遍的繼承做法,通過將子類的 prototype
指向父類的實(shí)例來實(shí)現(xiàn):
function Student() { } Student.prototype = new Person(); Student.prototype.name = '夏安'; Student.prototype.age = 18; const stud = new Student(); stud.getInfo();
在這種繼承方式中,stud
對(duì)象既是子類的實(shí)例,也是父類的實(shí)例。然而也有缺點(diǎn),在子類的構(gòu)造函數(shù)中無法通過傳遞參數(shù)對(duì)父類繼承的屬性值進(jìn)行修改,只能通過修改 prototype
的方式進(jìn)行修改。
1.2 調(diào)用父類的構(gòu)造函數(shù)
function Student(name, age, sex) { Person.call(this); this.name = name; this.age = age; this.sex = sex; } const stud = new Student('夏安', 18, 'male'); stud.greed(); // Hello, I am 夏安 stud.getInfo(); // Error
這種方式避免了原型鏈繼承的缺點(diǎn),直接在子類中調(diào)用父類的構(gòu)造函數(shù),在這種情況下,stud
對(duì)象只是子類的實(shí)例,不是父類的實(shí)例,而且只能調(diào)用父類實(shí)例中定義的方法,不能調(diào)用父類原型上定義的方法。
1.3 組合繼承
這種繼承方式是前面兩種繼承方式的結(jié)合體。
function Student(name, age, sex) { Person.call(this); this.name = name; this.age = age; this.sex = sex; } Student.prototype = new Person(); const stud = new Student('夏安', 18, 'male'); stud.greed(); stud.getInfo();
這種方式結(jié)合上面兩種繼承方式的優(yōu)點(diǎn),也是 Node 源碼中標(biāo)準(zhǔn)的繼承方式。唯一的問題是調(diào)用了父類的構(gòu)造函數(shù)兩次,分別是在設(shè)置子類的 prototype
和實(shí)例化子類新對(duì)象時(shí)調(diào)用的,這造成了一定的內(nèi)存浪費(fèi)。
1.4 原型繼承
利用一個(gè)空對(duì)象作為中介,將某個(gè)對(duì)象直接賦值給空對(duì)象構(gòu)造函數(shù)的原型。
function createObject(o) { // 創(chuàng)建臨時(shí)類 function f() { } // 修改類的原型為o, 于是f的實(shí)例都將繼承o上的方法 f.prototype = o return new f() }
這不就是Object.create
嗎? createObject
對(duì)傳入其中的對(duì)象執(zhí)行了一次淺復(fù)制,將構(gòu)造函數(shù)f
的原型直接指向傳入的對(duì)象。同樣也沒有解決修改原型鏈的缺點(diǎn)。
1.5 寄生式繼承
在原型式繼承的基礎(chǔ)上,增強(qiáng)對(duì)象,返回構(gòu)造函數(shù),或者說使用原型繼承對(duì)一個(gè)目標(biāo)對(duì)象進(jìn)行淺復(fù)制,增強(qiáng)這個(gè)淺復(fù)制的能力。
function Student() { const clone = Object.create(Person); clone.name = '夏安'; return clone; }
同樣也可以和之前的方法進(jìn)行組合,這里就不再贅述。
2. ES6 中的繼承
在 ES6 中可以直接使用 extends
關(guān)鍵字來實(shí)現(xiàn)繼承,形式上更加簡潔。我們前面也提到了,ES6 對(duì) Class
的改進(jìn)就是為了避免開發(fā)者過多地在語法細(xì)節(jié)中糾纏。
我們?cè)O(shè)計(jì)一個(gè) student
類來繼承之前定義的 person
類。
class Student extends Person { constructor(name, age, sex) { super(name, age); this.sex = sex; } getInfo() { return super.getInfo() + ',' + this.sex; } print() { const info = this.getInfo(); console.log(info); } } const student = new Student('夏安', 18, 'male'); student.print(); // 夏安,18,male
在代碼中我們定義了 Student
類,在它的構(gòu)造方法中調(diào)用了 super
方法,該方法調(diào)用了父類的構(gòu)造函數(shù),并將父類中的屬性綁定到子類上。
super
方法可以帶參數(shù),表示哪些父類的屬性會(huì)被繼承,在代碼中,子類使用 super
繼承了 Person
類的 name
以及 age
屬性,同時(shí)又聲明了一個(gè) sex
屬性。
在子類中,super
方法是必須要調(diào)用的,原因在于子類本身沒有自身的 this
對(duì)象,必須通過 super
方法拿到父類的 this
對(duì)象,可以在 super
函數(shù)調(diào)用前嘗試打印子類的 this
,代碼會(huì)出現(xiàn)未定義的錯(cuò)誤。
如果子類沒有定義 constructor
方法,那么在默認(rèn)的構(gòu)造方法內(nèi)部自動(dòng)調(diào)用 super
方法,并繼承父類的全部屬性。
同時(shí),在子類的構(gòu)造方法中,必須先調(diào)用 super
方法,然后才能調(diào)用 this
關(guān)鍵字聲明其他的屬性(如果存在的話),這同樣是因?yàn)樵?super
沒有調(diào)用之前,子類還沒有 this
這一緣故。
class Student extends Person { constructor(name, age, sex) { console.log(this); // Error super(name, age); this.sex = sex; } }
除了用在子類的構(gòu)造函數(shù)中,super
還可以用在類方法中來引用父類的方法。
class Student extends Person { constructor(name, age, sex) { super(name, age); this.sex = sex; } print() { const info = super.getInfo(); // 調(diào)用父類方法 console.log(info); } }
值得注意的是,super
只能調(diào)用父類方法,而不能調(diào)用父類的屬性,因?yàn)榉椒ㄊ嵌x在原型鏈上的,屬性則是定義在類的內(nèi)部(就像組合繼承那樣,屬性定義在類的內(nèi)部)。
class Student extends Person { constructor(name, age, sex) { super(name, age); this.sex = sex; } getInfo() { return super.name; // undefinded } }
此外,當(dāng)子類的函數(shù)被調(diào)用時(shí),使用的均為子類的 this
(修改父類的 this
得來),即使使用 super
來調(diào)用父類的方法,使用的仍然是子類的 this
。
class Person { constructor() { this.name = '夏安'; this.sex = 'male'; } getInfo() { return this.name + ',' + this.sex; } } class Student extends Person { constructor() { super(); this.name = '安夏'; this.sex = 'Female'; } print() { return super.getInfo(); } } const student = new Student(); console.log(student.print()); // 安夏,Female console.log(student.getInfo()); // 安夏,Female
在上面的例子中,super
調(diào)用了父類的方法,輸出的內(nèi)容卻是子類的屬性,說明 super
綁定了子類的 this
。
到此這篇關(guān)于JavaScript類的繼承全面示例講解的文章就介紹到這了,更多相關(guān)JS 類的繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
BootStrap柵格系統(tǒng)、表單樣式與按鈕樣式源碼解析
這篇文章主要為大家詳細(xì)解析了BootStrap柵格系統(tǒng)、表單樣式與按鈕樣式源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01基于javascript實(shí)現(xiàn)貪吃蛇經(jīng)典小游戲
這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12JavaScript函數(shù)Call、Apply原理實(shí)例解析
這篇文章主要介紹了JavaScript函數(shù)Call、Apply原理實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02用document.documentElement取代document.body的原因分析
ll建議用document.documentElement代替document.body2009-11-11基于JS實(shí)現(xiàn)頁面視頻video標(biāo)簽禁止下載(下載按鈕+右擊菜單)
最近做項(xiàng)目遇到這樣的需求,禁止用戶瀏覽頁面的時(shí)候下載頁面的視頻,網(wǎng)上看到下載視頻的方法有兩種,本文對(duì)每種方法做詳細(xì)分析,對(duì)js禁止下載視頻相關(guān)知識(shí)感興趣的朋友一起看看吧2024-02-02微信小程序?qū)崿F(xiàn)虎年春節(jié)頭像制作
春節(jié)來臨之際,看到有網(wǎng)友分享了網(wǎng)頁版的虎年頭像制作工具。本文將為大家介紹一個(gè)虎年春節(jié)頭像制作小程序,文中的示例代碼講解詳細(xì),需要的可以參考一下2022-02-02Bootstrap媒體對(duì)象的實(shí)現(xiàn)
在web頁面中,圖片居左,內(nèi)容居右排列,是非常常見的效果,它也就是媒體對(duì)象,它是一種抽象的樣式,可以用來構(gòu)建不同類型的組件。本文給大家介紹Bootstrap媒體對(duì)象的實(shí)現(xiàn),感興趣的朋友一起學(xué)習(xí)吧2016-05-05Layui實(shí)現(xiàn)主窗口和Iframe層參數(shù)傳遞
今天小編就為大家分享一篇Layui實(shí)現(xiàn)主窗口和Iframe層參數(shù)傳遞,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11傳參安全處理window.btoa base64加密,線性對(duì)稱加密
這篇文章主要介紹了傳參安全處理window.btoa base64加密,線性對(duì)稱加密,需要的朋友可以參考下2023-07-07