整合營銷服務商

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

          免費咨詢熱線:

          JavaScript面向對象編程-常用的兩種繼承方法

          JavaScript面向對象編程-常用的兩種繼承方法

          家都知道的,JavaScript這門語言在ES6出來之前是沒有類(class)這個概念的。

          所以JavaScript中的類都是通過原型鏈來實現的。

          既然能實現類,那同樣也就可以在JavaScript中實現面向對象的繼承了。(喜歡看書的朋友,可以去看一下《JavaScript高級程序設計》第三版6.3小節)。

          我們使用繼承主要是為了能實現代碼的抽象和代碼的復用,在應用層實現功能的封裝。

          在JavaScript中,繼承的實現比較復雜,坑也很多,什么屬性繼承、原型繼承、call/aplly繼承、原型鏈繼承、對象繼承、構造函數繼承、組合繼承、類繼承... 十幾種,看著都頭暈,對于小白來說,看多了都不知道用哪個好了。

          而且每一種都細講需要花很多時間,所以今天這里大致梳理常用的兩種給大家學習,一起來看看吧!

          JavaScript 中的繼承并不是明確規定的,而是通過模仿實現的。

          今天我們來講兩種,一個是原型鏈實現繼承、第二個借用構造函數

          先看一下父類

          父類

          方式一:原型鏈繼承

          實現方式:子類的原型指向父類的實例

          子類:

          代碼測試

          測試

          這種方式會存在的問題:

          1.引用類型的對象會被子類的所有實例共享(問題1解決)

          2.無法在創建子類的實例時,給父類的構造函數傳遞參數(問題2解決)

          方式二:借用構造函數(又稱為偽造對象、經典繼承)

          實現方式:在子類的構造函數中利用call(或者apply)方法執行父類構造函數(問題2解決),將執行對象設為子類的this,相當于把父類構造函數中的成員拷貝了一份到子類(問題1解決)

          子類

          子類

          測試代碼如下:

          測試代碼

          存在的問題:

          3.父類原型中定義的屬性無法被繼承

          以上兩種方法都是有存在問題的,所以我們現在就出現了第三種方法來實現,你知道第三種方式是怎么實現的嗎?歡迎在評論區留言哦!

          我們下次繼續聊繼承的其他方法。

          、對象冒充

          其原理如下:構造函數使用 this 關鍵字給所有屬性和方法賦值(即采用類聲明的構造函數方式)。因為構造函數只是一個函數,所以可使 Parent 構造函數 成為 Children 的方法,然后調用它。Children 就會收到 Parent 的構造函數中定義的屬性和方法。例如,用下面的方式定義 Parent 和 Children:


          原理:就是把 Parent 構造函數放到 Children 構造函數里面執行一次。那為什么不直接執行,非要轉個彎把 Parent 賦值給 Children 的 method 屬性再執行呢? 這跟 this 的指向有關,在函數內 this 是指向 window 的。當將 Parent 賦值給 Children 的 method 時, this 就指向了 Children 類的實例。

          二、原型鏈繼承

          眾所周知,JavaScript 是一門基于原型的語言,在 JavaScript 中 prototype 對象的任何屬性和方法都被傳遞給那個類的所有實例。原型鏈利用這種功能來實現繼承機制:


          注意:調用 Parent 的構造函數,沒有給它傳遞參數。這在原型鏈中是標準做法。要確保構造函數沒有任何參數。

          三、使用 call 或 applay 方法

          這個方法是與對象冒充方法最相似的方法,因為它也是通過改變了 this 的指向而實現繼承:


          apply 方法本人就不舉列了,它和 call 方法的區別在于它的第二個參數必須是數組。

          四、混合方式

          對象冒充的主要問題是必須使用構造函數方式,這不是最好的選擇。不過如果使用原型鏈,就無法使用帶參數的構造函數了。如何選擇呢?答案很簡單,兩者都用。 在 JavaScript 中創建類的最好方式是用構造函數定義屬性,用原型定義方法。這種方式同樣適用于繼承機制:


          五、使用 Object.create 方法

          Object.create 方法會使用指定的原型對象及其屬性去創建一個新的對象:


          @ 當執行 Children.prototype=Object.create(Parent.prototype) 這個語句后,Children 的 constructor 就被改變為 Parent ,因此需要將 Children.prototype.constructor 重 新指定為 Children 自身。

          六、extends 關鍵字實現繼承

          這個是 ES6 的語法糖,下面看下es6實現繼承的方法:


          上面代碼中,子類的constructor方法沒有調用super之前,就使用this關鍵字,結果報錯,而放在super方法之后就是正確的。子類Children的構造函數之中的super(),代表調用父類Parent的構造函數。這是必須的,否則 JavaScript 引擎會報錯。

          注意,super雖然代表了父類Parent的構造函數,但是返回的是子類Children的實例,即super內部的this指的是Children,因此super()在這里相當于Parent.prototype.constructor.call(this)。

          創: 前端二牛

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

          下面來看一個例子:

          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也能夠識別基于組合繼承創建的對象。


          主站蜘蛛池模板: 久久精品日韩一区国产二区| 在线观看一区二区精品视频| 末成年女A∨片一区二区| 久久亚洲综合色一区二区三区| 亲子乱av一区二区三区| 伊人色综合一区二区三区| 久久精品一区二区三区四区| bt7086福利一区国产| 免费一区二区视频| 亚洲乱码日产一区三区| 韩国福利一区二区美女视频| 精品一区二区三区无码免费直播| 国产一区玩具在线观看| 亚洲视频一区二区在线观看| 在线不卡一区二区三区日韩| 国产日韩一区二区三免费高清| 99久久精品午夜一区二区| 加勒比精品久久一区二区三区| 久久久久久综合一区中文字幕| 一区二区三区在线观看| 波多野结衣的AV一区二区三区 | 日韩人妻精品一区二区三区视频| 亚洲一区无码中文字幕乱码| 日韩电影在线观看第一区| 色欲综合一区二区三区| 国产一区二区三区樱花动漫| 台湾无码一区二区| 一区二区三区免费精品视频| 国产99久久精品一区二区| 中文字幕在线观看一区二区三区| 国产一区二区三区韩国女主播| 久久精品中文字幕一区| 久久中文字幕无码一区二区 | 国产一区二区三区在线看| 精品国产日韩亚洲一区在线| 久久久国产精品一区二区18禁| 久久中文字幕无码一区二区| 亚洲一区综合在线播放| 国产精品 一区 在线| 色国产在线视频一区| 亚洲一区二区三区四区视频|