整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JavaScript繼承(三)-組合繼承

          JavaScript繼承(三)-組合繼承

          創: 前端二牛

          借用構造函數繼承解決了原型鏈數據共享和無法向超類型傳遞參數的問題,但自身的缺陷是不能使用超類型原型中定義的方法。組合繼承是將原型鏈繼承和借用構造函數繼承組合到一起,從而發揮二者之長的一種繼承模式,也被稱作偽經典繼承。背后的思路是使用原型鏈實現原型屬性和方法的繼承,使用構造函數來實現實例屬性的繼承。這樣既通過在原型上定義方法實現了函數的復用,又能保證每個實例都有它自己的屬性。

          下面來看一個例子:

          1. function
          2. Human
          3. (
          4. name
          5. )
          6. {
          7. this
          8. .
          9. name
          10. =
          11. name
          12. ;
          13. this
          14. .
          15. colors
          16. =
          17. [
          18. 'yellow'
          19. ,
          20. 'white'
          21. ,
          22. 'black'
          23. ];
          24. }
          25. Human
          26. .
          27. prototype
          28. .
          29. sayName
          30. =
          31. function
          32. (){
          33. return
          34. this
          35. .
          36. name
          37. ;
          38. }
          39. //call的用法和apply相同,只不過call在傳遞參數的時候需要把
          40. //參數一一列出,而apply傳遞的是arguments
          41. function
          42. Person
          43. (
          44. name
          45. ,
          46. age
          47. )
          48. {
          49. //構造函數繼承屬性
          50. Human
          51. .
          52. call
          53. (
          54. this
          55. ,
          56. name
          57. );
          58. this
          59. .
          60. age
          61. =
          62. age
          63. ;
          64. }
          65. //使用原型鏈繼承方法
          66. Person
          67. .
          68. prototype
          69. =
          70. new
          71. Human
          72. ();
          73. Person
          74. .
          75. prototype
          76. .
          77. constructor
          78. =
          79. Person
          80. ;
          81. //定義自己的方法
          82. Person
          83. .
          84. prototype
          85. .
          86. sayAge
          87. =
          88. function
          89. (){
          90. return
          91. this
          92. .
          93. age
          94. ;
          95. }
          96. //測試使用
          97. var
          98. p1
          99. =
          100. new
          101. Person
          102. (
          103. 'Jack'
          104. ,
          105. 18
          106. );
          107. p1
          108. .
          109. colors
          110. .
          111. push
          112. (
          113. 'brone'
          114. );
          115. console
          116. .
          117. log
          118. (
          119. p1
          120. .
          121. colors
          122. );
          123. //["yellow", "white", "black", "brone"]
          124. console
          125. .
          126. log
          127. (
          128. p1
          129. .
          130. sayName
          131. (),
          132. p1
          133. .
          134. sayAge
          135. ());
          136. //Jack 18
          137. var
          138. p2
          139. =
          140. new
          141. Person
          142. (
          143. 'Rose'
          144. ,
          145. 20
          146. );
          147. console
          148. .
          149. log
          150. (
          151. p2
          152. .
          153. colors
          154. );
          155. //["yellow", "white", "black"]
          156. console
          157. .
          158. log
          159. (
          160. p2
          161. .
          162. sayName
          163. (),
          164. p2
          165. .
          166. sayAge
          167. ());
          168. //Rose 20

          在這個例子中首先聲明了一個 Human函數,然后使用原型模式定義了 sayName方法。聲明了 Person函數,通過構造函數模式繼承了 Human,但是這只能繼承 Human中聲明的屬性,也就是實例屬性,沒辦法繼承原型屬性和方法,于是緊接著將 Person的原型賦值為 Human的一個實例,通過原型鏈實現原型屬性和方法的繼承,然后添加了一個子類型特有的方法 sayName,這就是組合繼承。測試使用,結果既可以通過構造函數向超類型傳遞參數,也沒有 colors被共享的問題,同時還可以使用超類型原型上定義的方法 sayName,可以說非常完美。

          組合繼承避免了原型鏈和借用構造函數的缺陷,融合了它們的優點,成為JavaScript中最常用的繼承模式。而且,因為使用了原型鏈, instanceOf和 isPrototypeOf也能夠識別基于組合繼承創建的對象。

          為粉絲提出的建議 ,上一篇給大家講了call()和apply()的基本使用方法 。這一篇文章中為大家講解js繼承 , 內容中也會結合call()方法的使用 , 算是趁熱打鐵 。 沒有學過call()方法的要先學一下上篇文章哦 ~call()和apply()的用法

          原型繼承

          說到繼承 ,童靴們最先想到的可能是原型繼承了。如下:

          如上方法中通過b.prototype=new a("hkk",23)實現b的原型繼承了a , 但是這種方法有一個弊端 ,相信童靴們也能看出來 , 就是之后如果實例化函數b , 每個對象的屬性name和age值都是一樣的 ,都為“hkk”和23 。為了優化這個弊端 , 所以出現了組合繼承。

          組合繼承

          組合繼承結合call()方法和原型的方式實現繼承 , 如下:

          在函數b中使用call方法把父類a的屬性繼承 , 然后使用原型把父類原型上面的方法繼承過來 。此時b也擁有了a上面的所有屬性 ,所以就可以在實例化的時候為每個實例對象傳入不同的參數 。當然,這種方法也有一個不足之處,就是使用call()方法已經拿到父類所有的屬性 ,后面再使用原型時也會有父類所有屬性 ,如下:

          如上,盡管子類的屬性會覆蓋掉原型上面的屬性 ,可畢竟重復的東西看不來不太好。為了改善這個不足 , 我們需要封裝一個方法 ,如下:

          封裝如上函數 ,獲取到傳入函數的原型 , 在調用時傳入父類函數 ,如下:

          此時 ,子類b的原型就只會繼承到父類a原型上面的方法 , 而不是重復的基礎父類a的屬性了。

          最后還要注意的是 , 使用原型繼承會使子類的構造器指向父類a ,所以我們需要用如下方法讓b原型的構造器指向b.

          寫在這里 ,一個較完善的繼承也就完成了。下面附上完整的例子:

          你必須非常努力,才能看起來毫不費力 !

          關注小白前端,持續收到文章推送~

          s的繼承

          組合繼承是原性鏈繼承和構造函數繼承的合體,它汲取了二者各自的有點,同時又互相補充了各自的弱點,是一種應用十分廣泛的JavaScript繼承模式。下面分別從原性鏈繼承、構造函數繼承分別開始介紹,最后介紹二者的結合——組合繼承。

          一、原型鏈

          利用原型讓一個引用類型繼承另一個引用類型的屬性和方法

          每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。

          實現原性鏈的基本模式:

          function SuperType(){ //定義了一個父函數
           this.property=true; 
          } 
          SuperType.prototype.getSuperValue=function(){ //給父函數的原型鏈上添加一個getSuperValue的函數
           returnthis.property; 
          } 
          function Subtype(){ //定義一個子函數
           this.subproperty=false; 
          } 
          SubType.prototype=new SuperType(); //SubType實現了繼承SuperType 
          SubType.prototype.getSubValue=function(){ //給子函數添加方法
           return this.subproperty; 
          } 
          var instance=new SubType(); // 實例instance繼承子函數
          alert(instance.getSuperValue()); 
          

          最后的結果:intance指向SubType的原型,而SubType的原型又指向SuperType的原型,SuperType繼承了Object,所有函數的默認原型都是Object的實例

          問題:會產生引用類型值的問題

          比如,創建了一個子類的實例,如果對子類實例的屬性進行了修改,那么創建其他子類的時候都會收到影響,代碼如下:

          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 
          

          以上結果說明會影響其他實例的屬性值

          二、借用構造函數

          在子類型構造函數的內部調用超類型構造函數

          function SuperType(){ // 定義一個父函數
           this.colors=[“red”, “blue”, “green”]; 
          } 
          function SubType{}( // 定義一個子函數
           SuperType.call(this); // 繼承了父函數
          } 
          var instance1=new SubType(); // 實例instance1繼承子函數
          instance1.colors.push(“black”); 
          alert(intance1.colors); //red,blue,green,black 
          var instance2=new SubType(); // 實例instance2繼承子函數
          alert(instance2.colors); //red,blue,green 
          

          使用該方法可以在子類構造函數中向超類型構造函數傳遞參數,如下:

          function SuperType(name){ // 定義父函數
           this.name=name; 
          } 
          function SubType(){ // 定義子函數
          SuperType.call(this,“Nicholas”); //傳入參數,利用這個參數初始化父類構造函數中的name 
          this.age=29; 
          } 
          var instance=new SubType(); // 實例instance繼承子函數
          alert(instance.name); //Nicholas 
          alert(instance.age); //29 
          

          問題:不方便復用

          三、組合式繼承

          使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承

          示例代碼:

          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); //繼承SuperType的一部分,this指SubType, 
          this.age=age; //自己新定義的屬性age也可以進行賦值 
          } 
          SubType.prototype=new SuperType(); //利用原型繼承,可以使用父類的方法
           
          SubType.prototype.sayAge=function(){ //定義SubType特有的新方法 
           alert(this.age); 
          } 
          var instance1=new SubType(“Martin”, 10); 
          instance1.colors.push(“black”); 
          alert(instance1.colors); //red,blue,green,black 
          instance1.sayName(); //Martin 
          instance1.sayAge(); //10 
          var instance2=new SubType(“Greg”, 27); 
          alert(instance2.colors); //red,blue,green 
          instance2.sayName(); //Greg 
          instance2.sayAge(); //27 
          

          綜合例子:

          function Person(name, age) {
           this.name=name;
           this.age=age;
          }
          Person.prototype.hi=function() {
           console.log('Hi, my name is' + this.name) + ",I'm" + this.age + 'years old now.';
          };
          Person.prototype.LEGS_NUM=2;
          Person.prototype.ARMS_NUM=2;
          Person.prototype.walk=function() {
           console.log(this.name + "is walking...");
          }
          function Student(name, age, className) {
           Person.call(this, name, age);
           this.className=className;
          }
          Student.prototype=Objectcreate(Person.prototype);
          Student.prototype.constructor=Student;
          Student.prototype.hi=function() {
           console.log('Hi, my name is' + this.name + ", I'm" + this.age + "years old now, and from" + this.className + ".");
          }
          Student.prototype.learn=function(subject) {
           console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
          }
          // test
          var bosn=new Student('Bosn', 27, 'Class 3,Grade 2');
          bosn.hi(); // Hi, my name is Bosn, I'm 27 years old now and from Class3,Grage 2
          bosn.LEGS_NUM; // 2
          bosn.walk(); // Bosn is walking
          bosn.learn('math'); // Bosn is learning math t Class3, Grade 2.
          

          學習從來不是一個人的事情,要有個相互監督的伙伴,想要學習或交流前端問題的小伙伴可以私信“學習”小明獲取web前端入門資料,一起學習,一起成長!


          主站蜘蛛池模板: 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 久久99久久无码毛片一区二区| jazzjazz国产精品一区二区| 日韩精品一区二区三区影院| 麻豆AV天堂一区二区香蕉| 亚洲综合无码AV一区二区| 好爽毛片一区二区三区四无码三飞| 久久综合一区二区无码| 国产一区二区三区小说| 亚洲男女一区二区三区| 国产麻豆精品一区二区三区v视界| 成人精品一区二区三区电影| 天堂资源中文最新版在线一区 | 武侠古典一区二区三区中文| 日本片免费观看一区二区| 无码人妻精品一区二区三18禁| 夜色阁亚洲一区二区三区| 午夜一区二区在线观看| 无码中文人妻在线一区二区三区| 亚洲国产高清在线精品一区| 国产亚洲一区二区在线观看| 国产免费一区二区三区不卡| 国产一区二区在线观看app| 亚洲A∨精品一区二区三区 | 亚洲免费一区二区| 一区二区高清在线| 久久一区二区三区免费| 亚洲一区爱区精品无码| 精品视频一区二区三区免费 | 色窝窝无码一区二区三区| 久久久久久人妻一区精品| 香蕉免费一区二区三区| 末成年女AV片一区二区| 国产精品合集一区二区三区| 蜜臀AV免费一区二区三区| 亚州AV综合色区无码一区| 福利一区二区在线| 国产综合一区二区在线观看| 亚洲日本一区二区| 日韩精品一区二区三区国语自制| 国产在线一区二区三区在线|