摘要:原型式繼承利用一個(gè)空對(duì)象作為中介,將某個(gè)對(duì)象直接賦值給空對(duì)象構(gòu)造函數(shù)的原型。其中表示構(gòu)造函數(shù),一個(gè)類(lèi)中只能有一個(gè)構(gòu)造函數(shù),有多個(gè)會(huì)報(bào)出錯(cuò)誤如果沒(méi)有顯式指定構(gòu)造方法,則會(huì)添加默認(rèn)的方法,使用例子如下。
(關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo))
更新:在常用七種繼承方案的基礎(chǔ)之上增加了ES6的類(lèi)繼承,所以現(xiàn)在變成八種啦,歡迎加高級(jí)前端進(jìn)階群一起學(xué)習(xí)(文末)。
--- 2018.10.30
1、原型鏈繼承構(gòu)造函數(shù)、原型和實(shí)例之間的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)原型對(duì)象的指針。
繼承的本質(zhì)就是復(fù)制,即重寫(xiě)原型對(duì)象,代之以一個(gè)新類(lèi)型的實(shí)例。
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function() { return this.property; } function SubType() { this.subproperty = false; } // 這里是關(guān)鍵,創(chuàng)建SuperType的實(shí)例,并將該實(shí)例賦值給SubType.prototype SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function() { return this.subproperty; } var instance = new SubType(); console.log(instance.getSuperValue()); // true
原型鏈方案存在的缺點(diǎn):多個(gè)實(shí)例對(duì)引用類(lèi)型的操作會(huì)被篡改。
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"2、借用構(gòu)造函數(shù)繼承
使用父類(lèi)的構(gòu)造函數(shù)來(lái)增強(qiáng)子類(lèi)實(shí)例,等同于復(fù)制父類(lèi)的實(shí)例給子類(lèi)(不使用原型)
function SuperType(){ this.color=["red","green","blue"]; } function SubType(){ //繼承自SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.color.push("black"); alert(instance1.color);//"red,green,blue,black" var instance2 = new SubType(); alert(instance2.color);//"red,green,blue"
核心代碼是SuperType.call(this),創(chuàng)建子類(lèi)實(shí)例時(shí)調(diào)用SuperType構(gòu)造函數(shù),于是SubType的每個(gè)實(shí)例都會(huì)將SuperType中的屬性復(fù)制一份。
缺點(diǎn):
只能繼承父類(lèi)的實(shí)例屬性和方法,不能繼承原型屬性/方法
無(wú)法實(shí)現(xiàn)復(fù)用,每個(gè)子類(lèi)都有父類(lèi)實(shí)例函數(shù)的副本,影響性能
3、組合繼承組合上述兩種方法就是組合繼承。用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,用借用構(gòu)造函數(shù)技術(shù)來(lái)實(shí)現(xiàn)實(shí)例屬性的繼承。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ // 繼承屬性 // 第二次調(diào)用SuperType() SuperType.call(this, name); this.age = age; } // 繼承方法 // 構(gòu)建原型鏈 // 第一次調(diào)用SuperType() SubType.prototype = new SuperType(); // 重寫(xiě)SubType.prototype的constructor屬性,指向自己的構(gòu)造函數(shù)SubType 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
缺點(diǎn):
第一次調(diào)用SuperType():給SubType.prototype寫(xiě)入兩個(gè)屬性name,color。
第二次調(diào)用SuperType():給instance1寫(xiě)入兩個(gè)屬性name,color。
實(shí)例對(duì)象instance1上的兩個(gè)屬性就屏蔽了其原型對(duì)象SubType.prototype的兩個(gè)同名屬性。所以,組合模式的缺點(diǎn)就是在使用子類(lèi)創(chuàng)建實(shí)例對(duì)象時(shí),其原型中會(huì)存在兩份相同的屬性/方法。
4、原型式繼承利用一個(gè)空對(duì)象作為中介,將某個(gè)對(duì)象直接賦值給空對(duì)象構(gòu)造函數(shù)的原型。
function object(obj){ function F(){} F.prototype = obj; return new F(); }
object()對(duì)傳入其中的對(duì)象執(zhí)行了一次淺復(fù)制,將構(gòu)造函數(shù)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):
原型鏈繼承多個(gè)實(shí)例的引用類(lèi)型屬性指向相同,存在篡改的可能。
無(wú)法傳遞參數(shù)
另外,ES5中存在Object.create()的方法,能夠代替上面的object方法。
5、寄生式繼承核心:在原型式繼承的基礎(chǔ)上,增強(qiáng)對(duì)象,返回構(gòu)造函數(shù)
function createAnother(original){ var clone = object(original); // 通過(guò)調(diào)用 object() 函數(shù)創(chuàng)建一個(gè)新對(duì)象 clone.sayHi = function(){ // 以某種方式來(lái)增強(qiáng)對(duì)象 alert("hi"); }; return clone; // 返回這個(gè)對(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)(同原型式繼承):
原型鏈繼承多個(gè)實(shí)例的引用類(lèi)型屬性指向相同,存在篡改的可能。
無(wú)法傳遞參數(shù)
6、寄生組合式繼承結(jié)合借用構(gòu)造函數(shù)傳遞參數(shù)和寄生模式實(shí)現(xiàn)繼承
function inheritPrototype(subType, superType){ var prototype = Object.create(superType.prototype); // 創(chuàng)建對(duì)象,創(chuàng)建父類(lèi)原型的一個(gè)副本 prototype.constructor = subType; // 增強(qiáng)對(duì)象,彌補(bǔ)因重寫(xiě)原型而失去的默認(rèn)的constructor 屬性 subType.prototype = prototype; // 指定對(duì)象,將新創(chuàng)建的對(duì)象賦值給子類(lèi)的原型 } // 父類(lèi)初始化實(shí)例屬性和原型屬性 function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; // 借用構(gòu)造函數(shù)傳遞增強(qiáng)子類(lèi)實(shí)例屬性(支持傳參和避免篡改) function SubType(name, age){ SuperType.call(this, name); this.age = age; } // 將父類(lèi)原型指向子類(lèi) inheritPrototype(SubType, SuperType); // 新增子類(lèi)原型屬性 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"]
這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次SuperType?構(gòu)造函數(shù),并且因此避免了在SubType.prototype?上創(chuàng)建不必要的、多余的屬性。于此同時(shí),原型鏈還能保持不變;因此,還能夠正常使用instanceof?和isPrototypeOf()
這是最成熟的方法,也是現(xiàn)在庫(kù)實(shí)現(xiàn)的方法
7、混入方式繼承多個(gè)對(duì)象function MyClass() { SuperClass.call(this); OtherSuperClass.call(this); } // 繼承一個(gè)類(lèi) MyClass.prototype = Object.create(SuperClass.prototype); // 混合其它 Object.assign(MyClass.prototype, OtherSuperClass.prototype); // 重新指定constructor MyClass.prototype.constructor = MyClass; MyClass.prototype.myMethod = function() { // do something };
Object.assign會(huì)把 OtherSuperClass原型上的函數(shù)拷貝到 MyClass原型上,使 MyClass 的所有實(shí)例都可用 OtherSuperClass 的方法。
8、ES6類(lèi)繼承extendsextends關(guān)鍵字主要用于類(lèi)聲明或者類(lèi)表達(dá)式中,以創(chuàng)建一個(gè)類(lèi),該類(lèi)是另一個(gè)類(lèi)的子類(lèi)。其中constructor表示構(gòu)造函數(shù),一個(gè)類(lèi)中只能有一個(gè)構(gòu)造函數(shù),有多個(gè)會(huì)報(bào)出SyntaxError錯(cuò)誤,如果沒(méi)有顯式指定構(gòu)造方法,則會(huì)添加默認(rèn)的 constructor方法,使用例子如下。
class Rectangle { // constructor constructor(height, width) { this.height = height; this.width = width; } // Getter get area() { return this.calcArea() } // Method calcArea() { return this.height * this.width; } } const rectangle = new Rectangle(10, 20); console.log(rectangle.area); // 輸出 200 ----------------------------------------------------------------- // 繼承 class Square extends Rectangle { constructor(length) { super(length, length); // 如果子類(lèi)中存在構(gòu)造函數(shù),則需要在使用“this”之前首先調(diào)用 super()。 this.name = "Square"; } get area() { return this.height * this.width; } } const square = new Square(10); console.log(square.area); // 輸出 100
extends繼承的核心代碼如下,其實(shí)現(xiàn)和上述的寄生組合式繼承方式一樣
function _inherits(subType, superType) { // 創(chuàng)建對(duì)象,創(chuàng)建父類(lèi)原型的一個(gè)副本 // 增強(qiáng)對(duì)象,彌補(bǔ)因重寫(xiě)原型而失去的默認(rèn)的constructor 屬性 // 指定對(duì)象,將新創(chuàng)建的對(duì)象賦值給子類(lèi)的原型 subType.prototype = Object.create(superType && superType.prototype, { constructor: { value: subType, enumerable: false, writable: true, configurable: true } }); if (superType) { Object.setPrototypeOf ? Object.setPrototypeOf(subType, superType) : subType.__proto__ = superType; } }總結(jié)
1、函數(shù)聲明和類(lèi)聲明的區(qū)別
函數(shù)聲明會(huì)提升,類(lèi)聲明不會(huì)。首先需要聲明你的類(lèi),然后訪(fǎng)問(wèn)它,否則像下面的代碼會(huì)拋出一個(gè)ReferenceError。
let p = new Rectangle(); // ReferenceError class Rectangle {}
2、ES5繼承和ES6繼承的區(qū)別
ES5的繼承實(shí)質(zhì)上是先創(chuàng)建子類(lèi)的實(shí)例對(duì)象,然后再將父類(lèi)的方法添加到this上(Parent.call(this)).
ES6的繼承有所不同,實(shí)質(zhì)上是先創(chuàng)建父類(lèi)的實(shí)例對(duì)象this,然后再用子類(lèi)的構(gòu)造函數(shù)修改this。因?yàn)樽宇?lèi)沒(méi)有自己的this對(duì)象,所以必須先調(diào)用父類(lèi)的super()方法,否則新建實(shí)例報(bào)錯(cuò)。
《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承交流
MDN之Object.create()
MDN之Class
本人Github鏈接如下,歡迎各位Star
http://github.com/yygmind/blog
我是木易楊,網(wǎng)易高級(jí)前端工程師,跟著我每周重點(diǎn)攻克一個(gè)前端面試重難點(diǎn)。接下來(lái)讓我?guī)阕哌M(jìn)高級(jí)前端的世界,在進(jìn)階的路上,共勉!
如果你想加群討論每期面試知識(shí)點(diǎn),公眾號(hào)回復(fù)[加群]即可
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/98946.html
摘要:之前文章詳細(xì)介紹了的使用,不了解的查看進(jìn)階期。不同的引擎有不同的限制,核心限制在,有些引擎會(huì)拋出異常,有些不拋出異常但丟失多余參數(shù)。存儲(chǔ)的對(duì)象能動(dòng)態(tài)增多和減少,并且可以存儲(chǔ)任何值。這邊采用方法來(lái)實(shí)現(xiàn),拼成一個(gè)函數(shù)。 之前文章詳細(xì)介紹了 this 的使用,不了解的查看【進(jìn)階3-1期】。 call() 和 apply() call() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的 this 值和分...
摘要:使用指定的參數(shù)調(diào)用構(gòu)造函數(shù),并將綁定到新創(chuàng)建的對(duì)象。由構(gòu)造函數(shù)返回的對(duì)象就是表達(dá)式的結(jié)果。情況返回以外的基本類(lèi)型實(shí)例中只能訪(fǎng)問(wèn)到構(gòu)造函數(shù)中的屬性,和情況完全相反,結(jié)果相當(dāng)于沒(méi)有返回值。 定義 new 運(yùn)算符創(chuàng)建一個(gè)用戶(hù)定義的對(duì)象類(lèi)型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例。 ——(來(lái)自于MDN) 舉個(gè)栗子 function Car(color) { this.color = co...
摘要:中的詳解必修個(gè)多線(xiàn)程問(wèn)題總結(jié)個(gè)多線(xiàn)程問(wèn)題總結(jié)有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升開(kāi)源的運(yùn)行原理從虛擬機(jī)工作流程看運(yùn)行原理。 自己實(shí)現(xiàn)集合框架 (三): 單鏈表的實(shí)現(xiàn) 自己實(shí)現(xiàn)集合框架 (三): 單鏈表的實(shí)現(xiàn) 基于 POI 封裝 ExcelUtil 精簡(jiǎn)的 Excel 導(dǎo)入導(dǎo)出 由于 poi 本身只是針對(duì)于 ...
摘要:直接插入排序的算法重點(diǎn)在于尋找插入位置。也稱(chēng)縮小增量排序,是直接插入排序算法的一種更高效的改進(jìn)版本。希爾排序是非穩(wěn)定排序算法。簡(jiǎn)單選擇排序常用于取序列中最大最小的幾個(gè)數(shù)時(shí)。將新構(gòu)成的所有的數(shù)的十位數(shù)取出,按照十位數(shù)進(jìn)行排序,構(gòu)成一個(gè)序列。 1.直接插入排序 直接插入排序算法是排序算法中最簡(jiǎn)單的,但在尋找插入位置時(shí)的效率不高?;舅枷刖褪菍⒁粋€(gè)待排序的數(shù)字在已經(jīng)排序的序列中尋找找到一個(gè)插...
摘要:假定期望交換和的值序號(hào)實(shí)現(xiàn)方案中間變量備注按位操作符只適用類(lèi)型只適用類(lèi)型有腦洞先執(zhí)行對(duì)象解構(gòu)賦值推薦數(shù)組解構(gòu)賦值簡(jiǎn)書(shū)首發(fā)轉(zhuǎn)載請(qǐng)注明來(lái)自簡(jiǎn)書(shū) 假定let a = 1,b=10;期望交換a和b的值 序號(hào) 實(shí)現(xiàn)方案 中間變量? 備注 1 let c; c = a; a = b; b = c; ? 2 a ^= b; b ^=a; a ^=b MDN-按位操作符, 只適...
閱讀 2384·2021-11-23 09:51
閱讀 5854·2021-09-22 15:39
閱讀 3409·2021-09-02 15:15
閱讀 3559·2019-08-30 15:54
閱讀 2418·2019-08-30 15:53
閱讀 1459·2019-08-30 14:04
閱讀 2514·2019-08-29 18:33
閱讀 2480·2019-08-29 13:08