摘要:組合式繼承是最常用的繼承模式,但組合繼承使用過程中會被調(diào)用兩次一次是創(chuàng)建子類型的時候,另一次是在子類型構(gòu)造函數(shù)的內(nèi)部。
首先需要了解原型鏈機(jī)制: 原型鏈作為實現(xiàn)繼承的主要方法,其基本思想就是利用原型讓一個引用類型繼承另 一個引用類型的屬性和方法.
構(gòu)造函數(shù)、原型、實例之間的關(guān)系: 每個構(gòu)造函數(shù)都有一個原型對象(prototype),原型對象都包含一個指向構(gòu)造函數(shù)的指針(constructor),而實例都包含一個指向原型對象的內(nèi)部指針(__propto__).
自我理解: 其實每個Function都是Object基類的一個實例,所以每個Function上都有一個__proto__指向了Object.prototype.當(dāng)查找一個實例的屬性時,會先從這個實例的自定義屬性上找,如果沒有的話通過__proto__去實例所屬類的原型上去找,如果還沒有的話再通過原型(原型也是對象,只要是對象就有__proto__屬性)的__proto__到Object的原型上去找,一級一級的找,如果沒有就undefined(Object的__proto__返回undefined).
(一) 原型鏈繼承 :
function Parent(name) { this.name = name; } Parent.prototype.printName = function() { console.log("parent name:", this.name); } function Child(name) { this.name = name; } Child.prototype = new Parent("father"); Child.prototype.constructor = Child;//由于Child.prototype繼承Parent,導(dǎo)致constructor丟失 Child.prototype.printName = function() { console.log("child name:", this.name); } var child = new Child("son"); child.sayName(); // child name: son
這種方法存在兩個缺點(diǎn):
1.子類型無法給超類型傳遞參數(shù); 2.Child.prototype.sayName 必須寫在 Child.prototype = new Parent("father"); 之后,不然就會被覆蓋掉。
(二) 類式繼承:
function Parent(name) { this.name = name; } Parent.prototype.printName = function() { console.log("parent name:", this.name); } Parent.prototype.doSomthing = function() { console.log("parent do something!"); } function Child(name, parentName) { Parent.call(this, parentName); this.name = name; } Child.prototype.printName = function() { console.log("child name:", this.name); } var child = new Child("son"); child.printName(); // child name: son child.doSomthing(); // TypeError: child.doSomthing is not a function
相當(dāng)于 Parent 這個函數(shù)在 Child 函數(shù)中執(zhí)行了一遍,并且將所有與 this 綁定的變量都切換到了 Child 上,這樣就克服了第一種方式帶來的問題。
缺點(diǎn):沒有原型,每次創(chuàng)建一個 Child 實例對象時候都需要執(zhí)行一遍 Parent 函數(shù),無法復(fù)用一些公用函數(shù)。
(三) 組合式繼承:前兩種方式的結(jié)合
function Parent(name) { this.name = name; } Parent.prototype.printName = function() { console.log("parent name:", this.name); } Parent.prototype.doSomething = function() { console.log("parent do something!"); } function Child(name, parentName) { Parent.call(this, parentName);// 第二次調(diào)用 this.name = name; } Child.prototype = new Parent();// 第一次調(diào)用 Child.prototype.constructor = Child; Child.prototype.printName = function() { console.log("child name:", this.name); } var child = new Child("son"); child.printName(); // child name: son child.doSomething(); // parent do something!
組合式繼承是比較常用的一種繼承方法,其背后的思路是使用原型鏈實現(xiàn)對原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承。
這樣,既通過在原型上定義方法實現(xiàn)了函數(shù)復(fù)用,又保證每個實例都有它自己的屬性。
組合式繼承是 JS 最常用的繼承模式,但組合繼承使用過程中會被調(diào)用兩次:一次是創(chuàng)建子類型的時候,另一次是在子類型構(gòu)造函數(shù)的內(nèi)部。
第一次調(diào)用構(gòu)造函數(shù)顯然是沒有必要的,因為第一次調(diào)用構(gòu)造函數(shù)時候不需要函數(shù)內(nèi)部的那些實例屬性,這么寫只是想獲得其原型上的方法罷了,所以這時候你可能會這樣寫:
Child.prototype = Parent.prototype;
這樣寫顯然是不對的:
1.首先,你這樣寫的話相當(dāng)于是子類和父類都指向同一個對象,這時候如果你添加了新的方法給 Child 但實際上 Parent 并不需要,相當(dāng)于強(qiáng)行給 Parent 添加了一個未知的方法。
2.其次,仔細(xì)想想,這樣體現(xiàn)不出繼承的多態(tài)性,比如此時子類想要重寫父類的 getName 的方法,那么父類的方法也就會隨之修改,這顯然違背了多態(tài)性。
也就是說我們第一次調(diào)用構(gòu)造函數(shù)的時候,其實是不管構(gòu)造函數(shù)里面的內(nèi)容,這是我們可以new一個空函數(shù),將其prototype指向Parent.prototype,代碼如下:
(四) 寄生組合式繼承:
function Parent(name) { this.name = name; } Parent.prototype.printName = function() { console.log("parent name:", this.name); } function Child(name, parentName) { Parent.call(this, parentName); this.name = name; } function inheritPrototype(Parent, Child) { Child.prototype = Object.create(Parent.prototype); //修改 Child.prototype.constructor = Child; } inheritPrototype(Parent, Child); Child.prototype.printName = function() { console.log("child name:", this.name); } Child.prototype.constructor = Child; var parent = new Parent("father"); parent.printName(); // parent name: father var child = new Child("son", "father"); child.printName(); // child name: son
(五) ES 6 繼承:
class Parent { constructor(name) { this.name = name; } doSomething() { console.log("parent do something!"); } printName() { console.log("parent name:", this.name); } } class Child extends Parent { constructor(name, parentName) { super(parentName); this.name = name; } printName() { console.log("child name:", this.name); } } const child = new Child("son", "father"); child.printName(); // child name: son child.doSomething(); // parent do something! const parent = new Parent("father"); parent.printName(); // parent name: father
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/97881.html
摘要:今天閑來無事,看見幾行小字。又說所有對象,繼承終是。強(qiáng)行押韻一波這首詩的意思就是說的我今天沒有什么事情,然后無意中又在網(wǎng)上看到了任何對象都是從對象繼承而來的這句話。一時興起,便去驗證這句話。 今天閑來無事,看見幾行小字。又說所有對象,繼承終是Obj?!?強(qiáng)行押韻一波 這首詩的意思就是說的我今天沒有什么事情,然后無意中又在網(wǎng)上看到了任何對象都是從Object對象繼承而來的這句話。一時興...
摘要:繼承可以使得子類具有父類別的各種屬性和方法。繼承是類與類之間的關(guān)系。繼承的實質(zhì)就是兩次的原型搜索,像是實例屬性而不是繼承,才是繼承。更多用法見繼承。 前言 面試中最常會問到的問題:什么是繼承?如何分別用 ES5 和 ES6 實現(xiàn)?想要學(xué)習(xí)繼承,必須先學(xué)好原型與原型鏈,如果此部分還不清楚,請先學(xué)習(xí)此部分再來閱讀本文,可參考我的文章JS之原型與原型鏈或瀏覽其他相關(guān)的學(xué)習(xí)網(wǎng)站。 定義 繼承...
摘要:前奏的構(gòu)造函數(shù)就是函數(shù)的本身正文的繼承是通過函數(shù)結(jié)合原型而實現(xiàn)的,繼承是先實例化父類直接繼承使用這個詞來定義類的構(gòu)造函數(shù)是函數(shù)的繼承用與繼承是實例化子類對象的時候繼承父類然后繼承 最開始接觸的時候es5,js的類概念是 通過函數(shù) 實現(xiàn)的。 前奏:showImg(https://segmentfault.com/img/bVbuYHF?w=468&h=345);es5的構(gòu)造函數(shù)就...
摘要:前言見解有限,如有描述不當(dāng)之處,請幫忙及時指出,如有錯誤,會及時修正。倘若用的是中文搜索。所以最終的實例對象仍然能進(jìn)行正常的原型鏈回溯,回溯到原本的所有原型方法這樣通過一個巧妙的欺騙技巧,就實現(xiàn)了完美的繼承。 前言 見解有限,如有描述不當(dāng)之處,請幫忙及時指出,如有錯誤,會及時修正。 20180201更新: 修改用詞描述,如組合寄生式改成寄生組合式,修改多處筆誤(感謝@Yao Ding的...
摘要:但是,的本質(zhì)仍然是函數(shù),是構(gòu)造函數(shù)的另外一種寫法。報錯原生構(gòu)造函數(shù)的繼承對于一些原生的構(gòu)造函數(shù),比如,,,等,在是無法通過方法實現(xiàn)原生函數(shù)的內(nèi)部屬性,原生函數(shù)內(nèi)部的無法綁定,內(nèi)部屬性獲得不了。 在沒有學(xué)習(xí) ES6 之前,學(xué)習(xí) React,真的是一件非常痛苦的事情。即使之前你對 ES5 有著很好的基礎(chǔ),包括閉包、函數(shù)、原型鏈和繼承,但是 React 中已經(jīng)普遍使用 ES6 的語法,包括 ...
摘要:一般我們對這種構(gòu)造函數(shù)命名都會采用,并把它稱呼為類,這不僅是為了跟的理念保持一致,也是因為的內(nèi)建類也是這種命名。由生成的對象,其是。這是標(biāo)準(zhǔn)的規(guī)定。本文的主題是原型系統(tǒng)的變遷,所以并沒有涉及和對原型鏈的影響。 概述 JavaScript 的原型系統(tǒng)是最初就有的語言設(shè)計。但隨著 ES 標(biāo)準(zhǔn)的進(jìn)化和新特性的添加。它也一直在不停進(jìn)化。這篇文章的目的就是梳理一下早期到 ES5 和現(xiàn)在 ES6,...
閱讀 3286·2021-11-18 10:02
閱讀 3450·2021-10-11 10:58
閱讀 3382·2021-09-24 09:47
閱讀 1129·2021-09-22 15:21
閱讀 3952·2021-09-10 11:10
閱讀 3283·2021-09-03 10:28
閱讀 1753·2019-08-30 15:45
閱讀 2147·2019-08-30 14:22