摘要:繼承和前面兩篇文章中的知識(shí)非常相關(guān),如果對(duì)函數(shù)創(chuàng)建原理和原型鏈不熟悉,請(qǐng)猛戳高級(jí)程序設(shè)計(jì)筆記創(chuàng)建對(duì)象高級(jí)程序設(shè)計(jì)筆記原型圖解繼承,通俗的說,就是將自身不存在的屬性或方法,通過某種方式為自己所用文章分別介紹原型鏈繼承繼承借用構(gòu)造函數(shù)繼承組合繼
繼承和前面兩篇文章中的知識(shí)非常相關(guān),如果對(duì)函數(shù)創(chuàng)建原理和原型鏈不熟悉,請(qǐng)猛戳:
《javascript高級(jí)程序設(shè)計(jì)》筆記:創(chuàng)建對(duì)象
《javascript高級(jí)程序設(shè)計(jì)》筆記:原型圖解
繼承,通俗的說,就是將自身不存在的屬性或方法,通過某種方式為自己所用
文章分別介紹原型鏈繼承、call/apply繼承(借用構(gòu)造函數(shù)繼承)、組合繼承、原型式繼承、寄生式繼承、寄生組合式繼承
1. 原型鏈繼承核心:將父類的實(shí)例作為子類的原型
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } // 繼承自SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue());//true
簡(jiǎn)單的原型鏈分析
在《javascript高級(jí)程序設(shè)計(jì)》筆記:創(chuàng)建對(duì)象 的文章中,使用原型創(chuàng)建對(duì)象會(huì)存在多個(gè)實(shí)例對(duì)引用類型的操作會(huì)被篡改的問題,在上面同樣存在這個(gè)問題,如下:
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){} SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green,black"
兩個(gè)實(shí)例對(duì)象instance1和instance2的colors屬性指向相同,改變一個(gè)會(huì)影響另一個(gè)實(shí)例的屬性
缺陷:
(1)原型鏈繼承多個(gè)實(shí)例的引用類型屬性指向相同,存在篡改的可能
(2)不能傳遞參數(shù)
核心:使用父類的構(gòu)造函數(shù)來增強(qiáng)子類實(shí)例,等同于復(fù)制父類的實(shí)例給子類(不使用原型)
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } function SubType(name, age){ // 繼承自SuperType SuperType.call(this, name); this.age = age; } var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green" alert(instance1.name); // "Nicholas" alert(instance1.age); // 29
借用構(gòu)造函數(shù)繼承的核心就在于SuperType.call(this, name),“借調(diào)”了SuperType構(gòu)造函數(shù),這樣,SubType的每個(gè)實(shí)例都會(huì)將SuperType中的屬性復(fù)制一份
缺陷:
(1)只能繼承父類的實(shí)例屬性和方法,不能繼承原型屬性/方法
(2)無法實(shí)現(xiàn)復(fù)用,每個(gè)子類都有父類實(shí)例函數(shù)的副本,影響性能
核心:結(jié)合原型鏈繼承和構(gòu)造函數(shù)繼承通過調(diào)用父類構(gòu)造,繼承父類的屬性并保留傳參的優(yōu)點(diǎn),然后通過將父類實(shí)例作為子類原型,實(shí)現(xiàn)函數(shù)復(fù)用
其背后的思路是使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承,這樣,既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能保證每個(gè)實(shí)例都有它自己的屬性
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ //繼承屬性 SuperType.call(this, name); this.age = age; } // 繼承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27
圖解:
缺陷:
父類中的實(shí)例屬性和方法既存在于子類的實(shí)例中,又存在于子類的原型中,不過僅是內(nèi)存占用,因此,在使用子類創(chuàng)建實(shí)例對(duì)象時(shí),其原型中會(huì)存在兩份相同的屬性/方法
這個(gè)方法是javascript中最常用的繼承模式
4. 原型式繼承核心:直接將某個(gè)對(duì)象直接賦值給構(gòu)造函數(shù)的原型
function object(obj){ function F(){} F.prototype = obj; return new F(); }
object()對(duì)傳入其中的對(duì)象執(zhí)行了一次淺復(fù)制,將F的原型直接指向傳入的對(duì)象
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
缺點(diǎn):
(1)原型鏈繼承多個(gè)實(shí)例的引用類型屬性指向相同,存在篡改的可能
(2)無法傳遞參數(shù)
另外,ES5中存在Object.create()的方法,能夠代替上面的object方法
5. 寄生式繼承核心:在原型式繼承的基礎(chǔ)上,增強(qiáng)對(duì)象,返回構(gòu)造函數(shù)
function createAnother(original){ varclone=object(original); // 過調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象 clone.sayHi = function(){ // 以某種方式增強(qiáng)這個(gè)對(duì)象 alert("hi"); }; return clone; // 返回對(duì)象 }
函數(shù)的主要作用是為構(gòu)造函數(shù)新增屬性和方法,以增強(qiáng)函數(shù)
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
缺點(diǎn):
(1)原型鏈繼承多個(gè)實(shí)例的引用類型屬性指向相同,存在篡改的可能
(2)無法傳遞參數(shù)
核心:結(jié)合借用構(gòu)造函數(shù)傳遞參數(shù)和寄生模式實(shí)現(xiàn)繼承
function inheritPrototype(subType, superType){ var prototype = Object.create(superType.prototype); //創(chuàng)建對(duì)象 prototype.constructor = subType; // 增強(qiáng)對(duì)象 subType.prototype = prototype; // 指定對(duì)象 } // 父類初始化實(shí)例屬性和原型屬性 function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; // 借用構(gòu)造函數(shù)傳遞增強(qiáng)子類實(shí)例屬性(支持傳參和避免篡改) function SubType(name, age){ SuperType.call(this, name); this.age = age; } // 將父類原型指向子類 inheritPrototype(SubType, SuperType); // 新增子類原型屬性 SubType.prototype.sayAge = function(){ alert(this.age); } var instance1 = new SubType("xyc", 23); var instance2 = new SubType("lxy", 23); instance1.colors.push("2"); // ["red", "blue", "green", "2"] instance1.colors.push("3"); // ["red", "blue", "green", "3"]
圖解:
寄生組合繼承集合了前面幾種繼承優(yōu)點(diǎn),幾乎避免了上面繼承方式的所有缺陷,是執(zhí)行效率最高也是應(yīng)用面最廣的,就是實(shí)現(xiàn)的過程相對(duì)繁瑣
參考:
JS繼承的實(shí)現(xiàn)方式
面向?qū)ο蟮某绦蛟O(shè)計(jì)之繼承
MDN——Object.create()
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/89603.html
摘要:上一篇你不知道的筆記寫在前面這是年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響年是向上的一年在新的城市穩(wěn)定連續(xù)堅(jiān)持健身三個(gè)月早睡早起游戲時(shí)間大大縮減,學(xué)會(huì)生活。 上一篇:《你不知道的javascript》筆記_this 寫在前面 這是2019年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響2018年是向上的一年:在新的城市穩(wěn)定、...
摘要:繼承傳統(tǒng)的面向?qū)ο笳Z言,繼承是類與類之間的關(guān)系。原型繼承原型定義原型就是指構(gòu)造函數(shù)的屬性所引用的對(duì)象。創(chuàng)建構(gòu)造函數(shù)創(chuàng)建的實(shí)例對(duì)象張三李四就是對(duì)象的原型也是的原型在原型上創(chuàng)建一個(gè)屬性運(yùn)行和,并對(duì)比是否為同一個(gè)方法。 原文鏈接:http://www.hansmkiii.com/2018/07/06/javascript-node-1/ 面向?qū)ο?、原型、繼承 1、面向?qū)ο?1.1 什么...
摘要:思路是,使用原型鏈對(duì)原型屬性和方法進(jìn)行繼承,借用構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。注意使用寄生式繼承來為對(duì)象添加函數(shù),會(huì)由于不能做到函數(shù)復(fù)用而降低效率,這一點(diǎn)與構(gòu)造函數(shù)模式類似。無論什么情況下都會(huì)調(diào)用兩次超類型的構(gòu)造函數(shù)。 說明: 此摘要筆記系列是我最近看《JavaScript高級(jí)程序設(shè)計(jì)(第3版)》隨手所記。里面分條列舉了一些我認(rèn)為重要的、需要記下的、對(duì)我有幫助的點(diǎn),是按照我看的順序來的...
摘要:繼承的是超類型中構(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è)引用...
摘要:實(shí)現(xiàn)原型鏈的方式如下讓原型對(duì)象稱為另一個(gè)構(gòu)造函數(shù)的實(shí)例這個(gè)實(shí)例繼承了的屬性上述代碼繼承是通過來實(shí)現(xiàn),創(chuàng)建的實(shí)例,并將該實(shí)例賦給。無疑,集兩者之大成,這才是最常用的繼承模式。 原型鏈 JavaScript的繼承主要依靠原型鏈來實(shí)現(xiàn)的。我們知道,構(gòu)造函數(shù),原型,和實(shí)例之間的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)原型對(duì)象的指針。 實(shí)現(xiàn)原型鏈...
閱讀 2308·2021-11-24 09:39
閱讀 3038·2021-10-15 09:39
閱讀 3088·2021-07-26 23:38
閱讀 2288·2019-08-30 11:14
閱讀 3409·2019-08-29 16:39
閱讀 1713·2019-08-29 15:23
閱讀 778·2019-08-29 13:01
閱讀 2663·2019-08-29 12:29