摘要:繼承的是超類型中構(gòu)造函數(shù)中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結(jié)果是子類型實(shí)例中有兩組超類型的構(gòu)造函數(shù)中定義的屬性,一組在子類型的實(shí)例中,一組在子類型實(shí)例的原型中。
ECMAScript只支持實(shí)現(xiàn)繼承,主要依靠原型鏈來實(shí)現(xiàn)。與實(shí)現(xiàn)繼承對(duì)應(yīng)的是接口繼承,由于script中函數(shù)沒有簽名,所以無法實(shí)現(xiàn)接口繼承。
一、原型鏈基本思想:利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。
構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:每一個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)紙箱原型對(duì)象的內(nèi)部指針。
基本用法:
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function () { return this.property; } function SubType() { this.subproperty = false; } // 子的原型是父的對(duì)象 SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function () { return this.subproperty; } var instance = new SubType(); console.log(instance.getSuperValue()); // true
關(guān)系圖:
但實(shí)際上,SuperType也有自己的原型,就是Object,這個(gè)原型是默認(rèn)的。
所有函數(shù)的默認(rèn)原型都是Object的實(shí)例,因此默認(rèn)原型都會(huì)包含一個(gè)內(nèi)部指針,指向Object.prototype。
所以完整的關(guān)系圖應(yīng)該是
使用原型能夠做到繼承,但實(shí)際中并不多帶帶使用原型鏈來實(shí)現(xiàn)繼承,原因如下:
1、對(duì)于不需要‘父親’的私有屬性的繼承:我們知道原型來創(chuàng)建對(duì)象,使得所有的實(shí)例都擁有這些共享的屬性和方法,我們?cè)谑褂迷玩渷砝^承最主要的是SubType的原型變?yōu)镾uperType的實(shí)例對(duì)象,那么本來是Super實(shí)例私有的屬性property,且處于SubType的原型中成為SubType實(shí)例的共享屬性。
2、對(duì)于需要‘父親‘私有屬性的繼承:同一,我們知道會(huì)繼承父親的私有屬性,但我們無法通過傳入?yún)?shù)到’父親‘的構(gòu)造函數(shù)來實(shí)現(xiàn)屬性特有值的目的。
鑒于以上我們開始使用第二種繼承方式。
基本思想:在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)
function SuperType() { this.colors = ["red", "yellow", "black"]; } SuperType.prototype.getColor = function () { return this.colors; } function SubType() { // 繼承了SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("pink"); // ["red", "yellow", "black","pink"] console.log(instance1.colors); var instance2 = new SubType(); console.log(instance2.colors); // ["red", "yellow", "black"] console.log(instance2 instanceof SuperType); // false console.log(instance2.getColor()); // instance2.getColor is not a function
此方法是在子類型中調(diào)用了超(父)類型的構(gòu)造函數(shù),使構(gòu)造函數(shù)中的屬性初始化了。
繼承的是超類型中構(gòu)造函數(shù)中的屬性,如上繼承了colors屬性,但沒有繼承SuperType原型中的getcolor方法。
使用此方法,我們還可以傳遞參數(shù)對(duì)屬性進(jìn)行初始化
function SuperType(age) { this.age=age; } function SubType() { // 繼承了SuperType SuperType.call(this,18); } var instance1 = new SubType(); console.log(instance1.age); // 18
如果需要確保SuperType構(gòu)造函數(shù)不會(huì)重寫子類型的屬性,可以在調(diào)用超類型構(gòu)造函數(shù)后,再添加應(yīng)該在子類型定義的屬性。
缺點(diǎn):
1、超類型的原型不可見
2、所有屬性方法都必須寫在構(gòu)造函數(shù)中,所有類型都只能使用構(gòu)造函數(shù)模式創(chuàng)建
將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊。
思想:使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,借用構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。
function SuperType(age) { this.age = age; } SuperType.prototype.getAge = function () { return this.age; } function SubType(age) { // 繼承了SuperType SuperType.call(this, age); } SubType.prototype = new SuperType(20); var instance1 = new SubType(18); console.log(instance1.age); // 18 console.log(instance1.getAge()); // 18 console.log(instance1.__proto__.age); // 20 var instance2 = new SubType(17); instance2.__proto__.age=55; console.log(instance1.__proto__.age); // 55 console.log(instance2.__proto__.age); // 55
我們可以看到,實(shí)際上instance1和instance2的原型上仍然存在屬于SuperType的實(shí)例屬性的屬性。只是instance1和instance2有了各自的age屬性,不會(huì)再往原型上找。
instanceof和isPrototypeOf()也能夠用于識(shí)別基于組合繼承創(chuàng)建的對(duì)象。
組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷并融合了兩者的有點(diǎn),成為js中最常用的繼承模式。
思想:借助原型可以基于已有的對(duì)象創(chuàng)建新的對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類型。
function object(o) { function F() { }; F.prototype = o; return new F(); } var person = { name: "linda", friends: ["lily", "shirley"] }; var antherPerson = object(person); antherPerson.friends.push("tom"); console.log(antherPerson.name); // linda console.log(antherPerson.friends); // ["lily", "shirley", "tom]
這個(gè)方法和原型方法原理一樣,只不過把子類型的原型設(shè)置成超類型的實(shí)例對(duì)象包含在方法object中。
ECMAScript5中新增了object.create()方法來規(guī)范原型式繼承(作用與上述object函數(shù)作用類似),第一個(gè)參數(shù)是想要繼承的超類型的實(shí)例對(duì)象,第二個(gè)參數(shù)是子類型所具有的屬性。
var person={ name:"lily", age:12 } var anotherPerson=Object.create(person,{name:{value:"linda"}}); console.log(anotherPerson.name); // "linda"
第二個(gè)參數(shù)的寫法必須如上的格式。
支持Object.create()方法的瀏覽器有ie9+,F(xiàn)irefox4.+、Safari5+、Opera12+和Chrome
思想:與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象。
代碼:
function object(o){ function F(){} F.prototype=o; return new F(); } var person = { name: "lily", age: 12 } function createAnotherPerson(original){ var clone=object(original); clone.sayHi=function(){ console.log("hi"); } return clone; } var anotherPerson =createAnotherPerson(person); anotherPerson.sayHi(); // "hi" console.log(anotherPerson.name); // "linda"六、寄生組合式繼承
組合繼承是js最常用的繼承模式,可以結(jié)合不同的模式的優(yōu)點(diǎn),但組合繼承,每次都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時(shí)候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部。
上述造成的結(jié)果是子類型實(shí)例中有兩組超類型的構(gòu)造函數(shù)中定義的屬性,一組在子類型的實(shí)例中,一組在子類型實(shí)例的原型中。寄生組合式繼承可以解決上述缺點(diǎn)。
function Super(name) { this.name = name; } Super.prototype.sayName = function () { console.log(this.name); } function Sub(age) { Super.call(this, "linda"); this.age = age; } Sub.prototype = new Super(); Sub.constructor = Sub; var type=new Sub(); type.sayName(); // "linda" console.log(type.name); // "linda" console.log(type.__proto__.name); // undefined
思想:借用構(gòu)造函數(shù)來繼承屬性,借用原型鏈來繼承方法。即繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。
封裝一下即:
function Super(name) { this.name = name; } Super.prototype.sayName = function () { console.log(this.name); } function Sub(age) { Super.call(this, "linda"); this.age = age; } function object(o) { function F() { } F.prototype = o; return new F(); } function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); // 創(chuàng)建對(duì)象 prototype.constructor = subType; // 增強(qiáng)對(duì)象 subType.prototype = prototype; // 指定對(duì)象 } inheritPrototype(Sub, Super); var type = new Sub(); type.sayName(); // "linda" console.log(type.name); // "linda" console.log(type.__proto__.name); // undefined
這個(gè)模式的優(yōu)點(diǎn)體現(xiàn)在
1、只調(diào)用了一次Super構(gòu)造函數(shù),高效率
2、避免了在Sub.prototype上面創(chuàng)建不必要的多余的屬性
3、原型鏈保持不變
開發(fā)人員普遍認(rèn)為寄生組合式繼承是引用類型最理想的繼承范式
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100898.html
摘要:三種使用構(gòu)造函數(shù)創(chuàng)建對(duì)象的方法和的作用都是在某個(gè)特殊對(duì)象的作用域中調(diào)用函數(shù)。這種方式還支持向構(gòu)造函數(shù)傳遞參數(shù)。叫法上把函數(shù)叫做構(gòu)造函數(shù),其他無區(qū)別適用情境可以在特殊的情況下用來為對(duì)象創(chuàng)建構(gòu)造函數(shù)。 一、工廠模式 工廠模式:使用字面量和object構(gòu)造函數(shù)會(huì)有很多重復(fù)代碼,在此基礎(chǔ)上改進(jìn)showImg(https://segmentfault.com/img/bVbmKxb?w=456&...
摘要:創(chuàng)建一個(gè)新對(duì)象將構(gòu)造函數(shù)的作用域賦給新對(duì)象因此就指向了這個(gè)新對(duì)象執(zhí)行構(gòu)造函數(shù)中的代碼為這個(gè)新對(duì)象添加屬性返回新對(duì)象。 本章內(nèi)容 理解對(duì)象屬性 理解并創(chuàng)建對(duì)象 理解繼承 ECMA-262把對(duì)象定義為:無序?qū)傩缘募希鋵傩钥梢园局?、?duì)象或者函數(shù) 理解對(duì)象 創(chuàng)建對(duì)象 創(chuàng)建自定義對(duì)象的最簡(jiǎn)單方式就是創(chuàng)建一個(gè)Object的實(shí)例,再為它添加屬性和方法。 var person = new...
摘要:高程讀書筆記第六章理解對(duì)象創(chuàng)建自定義對(duì)象的方式有創(chuàng)建一個(gè)實(shí)例,然后為它添加屬性和方法。創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得屬性至于其他方法都是從繼承而來的。 JS高程讀書筆記--第六章 理解對(duì)象 創(chuàng)建自定義對(duì)象的方式有創(chuàng)建一個(gè)Object實(shí)例,然后為它添加屬性和方法。還可用創(chuàng)建對(duì)象字面量的方式 屬性類型 ECMAScript在定義只有內(nèi)部采用的特性時(shí),描述了屬性的各種特征...
摘要:分區(qū)函數(shù)返回一個(gè)布爾值,這意味著得到的分組的鍵類型是,于是它最多可以分為兩組是一組,是一組。當(dāng)遍歷到流中第個(gè)元素時(shí),這個(gè)函數(shù)執(zhí)行時(shí)會(huì)有兩個(gè)參數(shù)保存歸約結(jié)果的累加器已收集了流中的前個(gè)項(xiàng)目,還有第個(gè)元素本身。 一、收集器簡(jiǎn)介 把列表中的交易按貨幣分組: Map transactionsByCurrencies = transactions.stream().collect(groupi...
摘要:第六章抽象本章會(huì)介紹如何將語句組織成函數(shù)。關(guān)鍵字參數(shù)和默認(rèn)值目前為止,我們使用的參數(shù)都是位置參數(shù),因?yàn)樗鼈兊奈恢煤苤匾聦?shí)上比它們的名字更重要。參數(shù)前的星號(hào)將所有值放置在同一個(gè)元祖中。函數(shù)內(nèi)的變量被稱為局部變量。 第六章:抽象 本章會(huì)介紹如何將語句組織成函數(shù)。還會(huì)詳細(xì)介紹參數(shù)(parameter)和作用域(scope)的概念,以及遞歸的概念及其在程序中的用途。 懶惰即美德 斐波那契數(shù)...
閱讀 1850·2021-11-11 16:54
閱讀 2073·2019-08-30 15:56
閱讀 2385·2019-08-30 15:44
閱讀 1322·2019-08-30 15:43
閱讀 1878·2019-08-30 11:07
閱讀 833·2019-08-29 17:11
閱讀 1485·2019-08-29 15:23
閱讀 3021·2019-08-29 13:01