摘要:組合繼承最大的問(wèn)題就是無(wú)論在什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù)一次是在創(chuàng)建子類型原型的時(shí)候。好在,我們已經(jīng)找到了解決這個(gè)問(wèn)題方法寄生組合式繼承所謂寄生組合式繼承,即通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法。
寄生組合式繼承
組合繼承是JavaScript最常用的繼承模式。
不過(guò),它也有自己的不足。
組合繼承最大的問(wèn)題就是無(wú)論在什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù):
一次是在創(chuàng)建子類型原型的時(shí)候。
另外一次是在子類型構(gòu)造函數(shù)內(nèi)部。
子類型最終會(huì)包含超類型對(duì)象的全部實(shí)例屬性,但我們不得不在調(diào)用子類型構(gòu)造函數(shù)時(shí)重寫這些屬性。
function SuperType(name) { this.name = name; this.colors = ["red", "green", "blue"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name, age) { SuperType.call(this, name); //第二次調(diào)用父類型 this.age = age; } SubType.prototype = new SuperType(); // 第一次調(diào)用父類型 /* //到這里SubType的原型 SubType.prototye = { name: undefined, colors: ["red", "green", "blue"], __proto__: { constructor: SuperType, sayName: function(){ console.log(this.name); } } */ SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() { console.log(this.age); } /* //到這里SubType的原型 SubType.prototye = { name: undefined, colors: ["red", "green", "blue"], constructor: SubType, sayAge: function() { console.log(this.age); }, __proto__: { constructor: SuperType, sayName: function(){ console.log(this.name); } } */ var sub = new SubType(); /* // SubType的實(shí)例對(duì)象sub,其實(shí)是這樣的 sub = { name: undefined, colors: ["red", "green", "blue"], age: undefined, __proto__: { name: undefined, colors: ["red", "green", "blue"], constructor: SubType, sayAge: function() { console.log(this.age); }, __proto__: { constructor: SuperType, sayName: function(){ console.log(this.name); } } } } */
在第一次調(diào)用SuperType構(gòu)造函數(shù)時(shí),SubType.prototype會(huì)得到兩個(gè)屬性:name和colors;它們都是SuperType的實(shí)例屬性, 只不過(guò)現(xiàn)在位于SubType的原型中。
如果我們調(diào)用SubType構(gòu)造函數(shù)時(shí),又會(huì)調(diào)用一次SuperType構(gòu)造函數(shù),這一次有在新對(duì)象上創(chuàng)建了實(shí)例屬性name和colors。于是,這兩個(gè)屬性就屏蔽了原型中的兩個(gè)同名屬性。
有兩組name和colors屬性: 一組在實(shí)例上,一組在SubType原型中。
這就是調(diào)用兩次SuperType函數(shù)的結(jié)果。
好在,我們已經(jīng)找到了解決這個(gè)問(wèn)題方法——寄生組合式繼承
所謂寄生組合式繼承,即通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法。
其背后的基本思路:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需要的無(wú)非就是超類型原型的一個(gè)副本而已。本質(zhì)上,就是使用寄生式繼承來(lái)繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。
function object(o){ function F(){}; F.prototype = o; return new F(); } function SuperType(name) { this.name = name; this.colors = ["red", "green", "blue"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name, age){ SuperType.call(this, name); this.age = age; } function inheritPrototype(SubType, SuperType){ var prototype = object(SuperType.prototype); prototype.constructor = SubType; SubType.prototype = prototype; } inheritPrototype(SubType, SuperType); var instance = new SubType("Shaw", 18); instance.sayName(); //"Shaw"
這個(gè)實(shí)例中的inheritPrototype()函數(shù)實(shí)現(xiàn)了寄生組合式繼承的最簡(jiǎn)單形式。
這個(gè)函數(shù)接收兩個(gè)參數(shù): 子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。
在函數(shù)內(nèi)部,第一步是創(chuàng)建超類型原型的一個(gè)副本。第二步是為創(chuàng)建的副本添加constructor屬性,從而彌補(bǔ)因?yàn)橹貙懺投サ哪J(rèn)的constructor屬性。 最后一步,將新創(chuàng)建的對(duì)象(副本)賦值給子類型的原型。
這樣,我們就可以調(diào)用inheritPrototype()函數(shù)的語(yǔ)句,去替換前面例子中為子類型原型賦值的語(yǔ)句了。
這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次SuperType()構(gòu)造函數(shù),并且因此避免了在SubType.prototype上面創(chuàng)建不必要的、多余的屬性。與此同時(shí),原型鏈還能保持不變。
因此,還能夠正常使用instanceof和isPrototypeOf()。
開發(fā)人員普遍認(rèn)為寄生組合式繼承是引用類型最理想的繼承范式。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98652.html
摘要:以下是幾種中實(shí)現(xiàn)繼承的方式方法它們也是各自有各自的優(yōu)缺點(diǎn)選擇哪一種根據(jù)自己的應(yīng)用而定最適合自己的才是最好的通過(guò)原型鏈繼承通過(guò)原型對(duì)象繼承缺點(diǎn)引用類型的值在原型中會(huì)被所有實(shí)例共享不能向超類的構(gòu)造函數(shù)中傳遞參數(shù)借用構(gòu)造函數(shù)繼承借用構(gòu)造函數(shù)繼承是 以下是幾種js中實(shí)現(xiàn)繼承的方式方法,它們也是各自有各自的優(yōu)缺點(diǎn),選擇哪一種根據(jù)自己的應(yīng)用而定,最適合自己的才是最好的. 通過(guò)原型鏈繼承 funct...
摘要:寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個(gè)僅用于封裝繼承過(guò)程的函數(shù),該函數(shù)在內(nèi)部已某種方式來(lái)增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象。 這篇本來(lái)應(yīng)該是作為寫JS 面向?qū)ο蟮那白?,只是作為《javascript高級(jí)程序設(shè)計(jì)》繼承一章的筆記 原型鏈 code 實(shí)現(xiàn) function SuperType() { this.colors = [red,blu...
摘要:除此之外,在超類型的原型中定義的方法,對(duì)子類型而言也是不可兼得,結(jié)果所有類型都只能用構(gòu)造函數(shù)模式。創(chuàng)建對(duì)象增強(qiáng)對(duì)象指定對(duì)象繼承屬性這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次構(gòu)造函數(shù)。 1、原型鏈 原型鏈的基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象;原型對(duì)象都包含著一個(gè)指向構(gòu)造函數(shù)的指針;實(shí)例都包含一個(gè)指向原型對(duì)象的...
摘要:因?yàn)檫@造成了繼承鏈的紊亂,因?yàn)榈膶?shí)例是由構(gòu)造函數(shù)創(chuàng)建的,現(xiàn)在其屬性卻指向了為了避免這一現(xiàn)象,就必須在替換對(duì)象之后,為新的對(duì)象加上屬性,使其指向原來(lái)的構(gòu)造函數(shù)。這個(gè)函數(shù)接收兩個(gè)參數(shù)子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。 最近一直在研究js面向?qū)ο?,原型鏈繼承是一個(gè)難點(diǎn),下面是我對(duì)繼承的理解以下文章借鑒自CSDN季詩(shī)筱的博客 原型鏈繼承的基本概念: ES中描述了原型鏈的概念,并將原型鏈作為實(shí)現(xiàn)...
摘要:通常有這兩種繼承方式接口繼承和實(shí)現(xiàn)繼承。理解繼承的工作是通過(guò)調(diào)用函數(shù)實(shí)現(xiàn)的,所以是寄生,將繼承工作寄托給別人做,自己只是做增強(qiáng)工作。適用基于某個(gè)對(duì)象或某些信息來(lái)創(chuàng)建對(duì)象,而不考慮自定義類型和構(gòu)造函數(shù)。 一、繼承的概念 繼承,是面向?qū)ο笳Z(yǔ)言的一個(gè)重要概念。通常有這兩種繼承方式:接口繼承和實(shí)現(xiàn)繼承。接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。 《JS高程》里提到:由于函數(shù)沒(méi)有簽名,...
閱讀 2228·2021-09-30 09:47
閱讀 990·2021-08-27 13:01
閱讀 2973·2019-08-30 15:54
閱讀 3699·2019-08-30 15:53
閱讀 839·2019-08-29 14:07
閱讀 727·2019-08-28 18:16
閱讀 815·2019-08-26 18:37
閱讀 1422·2019-08-26 13:27