整合營銷服務商

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

          免費咨詢熱線:

          在面向對象編程中,子類可以覆蓋父類的方法

          面向對象編程中,子類可以覆蓋父類的方法,但有時你可能需要在子類中調用被覆蓋的父類方法。這通常有幾種不同的方法,具體取決于你使用的編程語言。以下是一些常見編程語言中調用父類被覆蓋方法的方式:

          ### Java

          在Java中,可以使用`super`關鍵字來調用父類的方法:

          ```

          ocation 對象

          location 對象包含有關當前 URL 的信息。

          location 對象是 Window 對象的一個部分,可通過 window.location 屬性來訪問。

          <html>
          <head>
          <script type="text/javascript">
          function currLocation()
          {
          alert(window.location);
          }
          function newLocation()
          {
          window.location="/index.html";
          }
          </script>
          </head>
          <body>
          <input type="button" onclick="currLocation()" value="顯示當前的 URL">
          <input type="button" onclick="newLocation()" value="改變 URL">
          </body>
          </html>

          location 對象屬性

          hash 設置或返回從井號 (#) 開始的 URL(錨)。

          host 設置或返回主機名和當前 URL 的端口號。

          hostname 設置或返回當前 URL 的主機名。

          href 設置或返回完整的 URL。

          pathname 設置或返回當前 URL 的路徑部分。

          port 設置或返回當前 URL 的端口號。

          protocol 設置或返回當前 URL 的協議。

          search 設置或返回從問號 (?) 開始的 URL(查詢部分)。

          http://example.com:1234/test/test.htm#part2:

          hash: #part2

          host:example.com:1234

          hostname:example.com

          href:http://example.com:1234/test.htm#part2

          pathname:/test/test.htm

          port:1234

          protocol:http:

          假設當前的 URL 是: http://www.w3school.com.cn/tiy/t.asp?f=hdom_loc_search

          search:?f=hdom_loc_search

          <script type="text/javascript">
          document.write(location.host);
          </script>

          輸出:example.com:1234

          location 對象方法

          assign() 加載新的文檔。

          reload() 重新加載當前文檔。

          replace() 用新的文檔替換當前文檔。

          assign() 方法可加載一個新的文檔。

          location.assign(URL)

          <html>
          <head>
          <script type="text/javascript">
          function newDoc()
          {
          window.location.assign("http://www.w3school.com.cn");
          }
          </script>
          </head>
          <body>
          <input type="button" value="Load new document" onclick="newDoc()" />
          </body>
          </html>

          reload() 方法用于重新加載當前文檔。

          location.reload(bool)

          參數如果是false則從瀏覽器的緩存中重載,如果為true則從服務器上重載,默認值為false;

          <html>
          <head>
          <script type="text/javascript">
          function reloadPage(){
          window.location.reload();
          }
          </script>
          </head>
          <body>
          <input type="button" value="Reload page" onclick="reloadPage()" />
          </body>
          </html>

          replace() 方法可用一個新文檔取代當前文檔。

          location.replace(newURL)

          replace() 方法不會在 History 對象中生成一個新的記錄。當使用該方法時,新的 URL 將覆蓋 History 對象中的當前記錄。

          <html>
          <head>
          <script type="text/javascript">
          function replaceDoc(){
          window.location.replace("http://www.w3school.com.cn");
          }
          </script>
          </head>
          <body>
          <input type="button" value="Replace document" onclick="replaceDoc()" />
          </body>
          </html>

          實例:ThinkPHP框架

          <a href='{:U('Circle/circleDetail',array('id'=>$vo['share_id']))}'> <!-- 此種方式會影響頁面顯示效果 -->
          <div class="item item-avatar item-button-right">
          <img src="{$vo.head_pic}">
          <h2>{$vo.user_name}</h2>
          <p>{:friend_date($vo['public_time'])}</p>
          <i class=" button button-icon button-outline button-assertive" onclick="setCollection(this, '{$vo.share_id}', '{$user.user_id}')">{$vo.isCollection}</i>
          </div>
          </a>

          代替a鏈接功能

          . 原型鏈

          原型鏈是ES5中實現繼承的主要手段, 因此相對比較重要, 我們需要深入理解原型鏈.

          1.1. 深入理解原型鏈

          先來回顧一下構造函數、原型和實例的關系:

          • 每個構造函數都有一個原型對象, 通過prototype指針指向該原型對象.
          • 原型對象都包含一個指向構造函數的指針, 通過constructor指針, 指向構造函數
          • 而實例都包含一個指向原型對象的內部指針, 該內部指針我們通常使用__proto__來描述.

          思考如下情況:

          • 我們知道, 可以通過Person.prototype = {}的方式來重寫原型對象.
          • 假如, 我們后面賦值的不是一個{}, 而是另外一個類型的實例, 結果會是怎么樣呢?
          • 顯然,此時的原型對象將包含一個指向另一個原型的指針,相應地,另一個原型中也包含著一個指向另一個構造函數的指針。
          • 假如另一個原型又是另一個類型的實例,那么上述關系依然成立,如此層層遞進,就構成了實例與原型的鏈條。這就是所謂原型鏈的基本概念。

          有些抽象, 我們通過代碼來理解:

          // 創建Person構造函數
          function Person() {
          }
          
          // 設置Animal的原型
          Person.prototype = {
          }
          

          我們將代碼修改成原型鏈的形式:

          // 1.創建Animal的構造函數
          function Animal() {
              this.animalProperty = "Animal"
          }
          
          // 2.給Animal的原型中添加一個方法
          Animal.prototype.animalFunction = function () {
              alert(this.animalProperty)
          }
          
          // 3.創建Person的構造函數
          function Person() {
              this.personProperty = "Person"
          }
          
          // 4.給Person的原型對象重新賦值
          Person.prototype = new Animal()
          
          // 5.給Person添加屬于自己的方法
          Person.prototype.personFunction = function () {
              alert(this.personProperty)
          }
          
          // 6.創建Person的實例
          var person = new Person()
          person.animalFunction()
          person.personFunction()
          

          代碼解析:

          • 代碼有一些復雜, 但是如果你希望學習好原型鏈, 必須耐心去看一看上面的代碼, 你會發現其實都是我們學習過的.
          • 重點我們來看第4步代碼: 給Person.prototype賦值了一個Animal的實例. 也就是Person的原型變成了Animal的實例.
          • Animal實例本身有一個__proto__可以指向Animal的原型.
          • 那么, 我們來思考一個問題: 如果現在搜索一個屬性或者方法, 這個時候會按照什么順序搜索呢?
            • 第一步, 在person實例中搜索, 搜索到直接返回或者調用函數. 如果沒有執行第二步.
            • 第二步, 在Person的原型中搜索, Person的原型是誰? Animal的實例. 所以會在Animal的實例中搜索, 無論是屬性還是方法, 如果搜索到則直接返回或者執行. 如果沒有, 執行第三步.
            • 第三步, 在Animal的原型中搜索, 搜索到返回或者執行, 如果沒有, 搜索結束. (當然其實還有Object, 但是先不考慮)

          畫圖解析可能更加清晰:

          當代碼執行到第3步(上面代碼的序號)的時候, 如圖所示:

          img

          當代碼執行第4步(上面代碼的序號)時, 發生了如圖所示的變化

          • 注意圖片中的紅色線, 原來指向的是誰, 現在指向的是誰.

          img

          代碼繼續執行

          • Person.prototype.personFunction = function (){}
          • 當執行第5步, 也就是給Person的原型賦值了一個函數時, 事實上在給new Animal(Animal的實例)賦值了一個新的方法.

          img

          代碼繼續執行, 我們創建了一個Person對象

          • 創建Person對象, person對象會有自己的屬性, personProperty.
          • 另外, person對象有一個__prototype__指向Person的原型.
          • Person的原型是誰呢? 就是我們之前的new Animal(Animal的一個實例), 所以會指向它.

          原型鏈簡單總結:

          • 通過實現原型鏈,本質上擴展了本章前面介紹的原型搜索機制。
          • 當以讀取模式訪問一個實例屬性時,首先會在實例中搜索該屬性。如果沒有找到該屬性,則會繼續搜索實例的原型。在通過原型鏈實現繼承的情況下,搜索過程就得以沿著原型鏈繼續向上。
          • 在找不到屬性或方法的情況下,搜索過程總是要一環一環地前行到原型鏈末端才會停下來。

          1.2. 原型和實例的關系

          如果我們希望確定原型和實例之間的關系, 有兩種方式:

          • 第一種方式是使用instanceof操作符,只要用這個操作符來測試實例與原型鏈中出現過的構造函數,結果就會返回true。
          • 第二種方式是使用isPrototypeOf()方法。同樣,只要是原型鏈中出現過的原型,都可以說是該原型鏈所派生的實例的原型,因此isPrototypeOf()方法也會返回true

          instanceof操作符

          // instanceof
          alert(person instanceof Object) // true
          alert(person instanceof Animal) // true
          alert(person instanceof Person) // true
          

          isPrototypeOf()函數

          // isPrototypeOf函數
          alert("isPrototypeOf函數函數")
          alert(Object.prototype.isPrototypeOf(person)) // true
          alert(Animal.prototype.isPrototypeOf(person)) // true
          alert(Person.prototype.isPrototypeOf(person)) // true
          

          1.3. 添加新的方法

          添加新的方法

          • 在第5步操作中, 我們為子類型添加了一個新的方法. 但是這里有一個注意點.
          • 無論是子類中添加新的方法, 還是對父類中方法進行重寫. 都一定要將添加方法的代碼, 放在替換原型語句之后.
          • 否則, 我們添加的方法將會無效.

          錯誤代碼引起的代碼:

          // 1.定義Animal的構造函數
          function Animal() {
              this.animalProperty = "Animal"
          }
          
          // 2.給Animal添加方法
          Animal.prototype.animalFunction = function () {
              alert(this.animalProperty)
          }
          
          // 3.定義Person的構造函數
          function Person() {
              this.personProperty = "Person"
          }
          
          // 4.給Person添加方法
          Person.prototype.personFunction = function () {
              alert(this.personProperty)
          }
          
          // 5.給Person賦值新的原型對象
          Person.prototype = new Animal()
          
          // 6.創建Person對象, 并且調用方法
          var person = new Person()
          person.personFunction() // 不會有任何彈窗, 因為找不到該方法
          

          代碼解析:

          • 執行上面的代碼不會出現任何的彈窗, 因為我們添加的方法是無效的, 被賦值的新的原型覆蓋了.
          • 正確的辦法是將第4步和第5步操作換一下位置即可.

          總結

          • 其實這個問題沒什么好說的, 只要你理解了原型鏈(好好看看我上面畫的圖, 或者自己畫一下圖)
          • 但是, 切記在看圖的過程中一樣掃過, 因為這會讓你錯過很多細節, 對原型鏈的理解就會出現問題.

          1.4. 原型鏈的問題

          原型鏈對于繼承來說:

          • 原型鏈似乎對初學JavaScript原型的人來說, 已經算是比較高明的設計技巧了, 有些人理解起來都稍微有些麻煩.
          • 但是, 這種設計還存在一些缺陷, 不是最理性的解決方案. (但是后續的解決方案也是依賴原型鏈, 無論如何都需要先理解它)

          原型鏈存在的問題:

          • 原型鏈存在最大的問題是關于引用類型的屬性.
          • 通過上面的原型實現了繼承后, 子類的person對象繼承了(可以訪問)Animal實例中的屬性(animalProperty).
          • 但是如果這個屬性是一個引用類型(比如數組或者其他引用類型), 就會出現問題.

          引用類型的問題代碼:

          // 1.定義Animal的構造函數
          function Animal() {
              this.colors = ["red", "green"]
          }
          
          // 2.給Animal添加方法
          Animal.prototype.animalFunction = function () {
              alert(this.colors)
          }
          
          // 3.定義Person的構造函數
          function Person() {
              this.personProperty = "Person"
          }
          
          // 4.給Person賦值新的原型對象
          Person.prototype = new Animal()
          
          // 5.給Person添加方法
          Person.prototype.personFunction = function () {
              alert(this.personProperty)
          }
          
          // 6.創建Person對象, 并且調用方法
          var person1 = new Person()
          var person2 = new Person()
          
          alert(person1.colors) // red,green
          alert(person2.colors) // red,green
          
          person1.colors.push("blue")
          
          alert(person1.colors) // red,green,blue
          alert(person2.colors) // red,green,blue
          

          代碼解析:

          • 我們查看第6步的操作
          • 創建了兩個對象, 并且查看了它們的colors屬性
          • 修改了person1中的colors屬性, 添加了一個新的顏色blue
          • 再次查看兩個對象的colors屬性, 會發現person2的colors屬性也發生了變化
          • 兩個實例應該是相互獨立的, 這樣的變化如果我們不制止將會在代碼中引發一些列問題.

          原型鏈的其他問題:

          • 在創建子類型的實例時,不能向父類型的構造函數中傳遞參數。
          • 實際上,應該說是沒有辦法在不影響所有對象實例的情況下,給父類型的構造函數傳遞參數。
          • 從而可以修改父類型中屬性的值, 在創建構造函數的時候就確定一個值.

          二. 經典繼承

          為了解決原型鏈繼承中存在的問題, 開發人員提供了一種新的技術: constructor stealing(有很多名稱: 借用構造函數或經典繼承或偽造對象), steal是偷竊的意思, 但是這里可以翻譯成借用.

          2.1. 經典繼承的思想

          經典繼承的做法非常簡單: 在子類型構造函數的內部調用父類型構造函數.

          • 因為函數可以在任意的時刻被調用
          • 因此通過apply()和call()方法也可以在新創建的對象上執行構造函數.

          經典繼承代碼如下:

          // 創建Animal的構造函數
          function Animal() {
              this.colors = ["red", "green"]
          }
          
          // 創建Person的構造函數
          function Person() {
              // 繼承Animal的屬性
              Animal.call(this)
          
              // 給自己的屬性賦值
              this.name = "Coderwhy"
          }
          
          // 創建Person對象
          var person1 = new Person()
          var person2 = new Person()
          
          alert(person1.colors) // red,greem
          alert(person2.colors) // red,greem
          person1.colors.push("blue")
          alert(person1.colors) // red,green,blue
          alert(person2.colors) // red,green
          

          代碼解析:

          • 我們通過在Person構造函數中, 使用call函數, 將this傳遞進去.
          • 這個時候, 當Animal中有相關屬性初始化時, 就會在this對象上進行初始化操作.
          • 這樣就實現了類似于繼承Animal屬性的效果.

          這個時候, 我們也可以傳遞參數, 修改上面的代碼:

          // 創建Animal構造函數
          function Animal(age) {
              this.age = age
          }
          
          // 創建Person構造函數
          function Person(name, age) {
              Animal.call(this, age)
              this.name = name
          }
          
          // 創建Person對象
          var person = new Person("Coderwhy", 18)
          alert(person.name)
          alert(person.age)
          

          2.2. 經典繼承的問題

          經典繼承的問題:

          • 對于經典繼承理解比較深入, 你已經能發現: 經典繼承只有屬性的繼承, 無法實現方法的繼承.
          • 因為調用call函數, 將this傳遞進去, 只能將父構造函數中的屬性初始化到this中.
          • 但是如果函數存在于父構造函數的原型對象中, this中是不會有對應的方法的.

          回顧原型鏈和經典繼承:

          • 原型鏈存在的問題是引用類型問題和無法傳遞參數, 但是方法可以被繼承
          • 經典繼承是引用類型沒有問題, 也可以傳遞參數, 但是方法無法被繼承.
          • 怎么辦呢? 將兩者結合起來怎么樣?

          三. 組合繼承

          如果你認識清楚了上面兩種實現繼承的方式存在的問題, 就可以很好的理解組合繼承了.

          組合繼承(combination inheritance, 有時候也稱為偽經典繼承), 就是將原型鏈和經典繼承組合在一起, 從而發揮各自的優點.

          3.1. 組合繼承的思想

          組合繼承:

          • 組合繼承就是發揮原型鏈和經典繼承各自的優點來完成繼承的實現.
          • 使用原型鏈實現對原型屬性和方法的繼承.
          • 通過經典繼承實現對實例屬性的繼承, 以及可以在構造函數中傳遞參數.

          組合繼承的代碼:

          // 1.創建構造函數的階段
          // 1.1.創建Animal的構造函數
          function Animal(age) {
              this.age = age
              this.colors = ["red", "green"]
          }
          
          // 1.2.給Animal添加方法
          Animal.prototype.animalFunction = function () {
              alert("Hello Animal")
          }
          
          // 1.3.創建Person的構造函數
          function Person(name, age) {
              Animal.call(this, age)
              this.name = name
          }
          
          // 1.4.給Person的原型對象重新賦值
          Person.prototype = new Animal(0)
          
          // 1.5.給Person添加方法
          Person.prototype.personFunction = function () {
              alert("Hello Person")
          }
          
          // 2.驗證和使用的代碼
          // 2.1.創建Person對象
          var person1 = new Person("Coderwhy", 18)
          var person2 = new Person("Kobe", 30)
          
          // 2.2.驗證屬性
          alert(person1.name + "-" + person1.age) // Coderwhy,18
          alert(person2.name + "-" + person2.age) // Kobe,30
          
          // 2.3.驗證方法的調用
          person1.animalFunction() // Hello Animal
          person1.personFunction() // Hello Person
          
          // 2.4.驗證引用屬性的問題
          person1.colors.push("blue")
          alert(person1.colors) // red,green,blue
          alert(person2.colors) // red,green
          

          代碼解析:

          • 根據前面學習的知識, 結合當前的代碼, 大家應該可以理解上述代碼的含義.
          • 但是我還是建議大家一定要多手動自己來敲代碼, 來理解其中每一個步驟.
          • 記住: 看懂, 聽懂不一定真的懂, 自己可以寫出來, 才是真的懂了.

          3.2. 組合繼承的分析

          組合繼承是JavaScript最常用的繼承模式之一.

          • 如果你理解到這里, 點到為止, 那么組合來實現繼承只能說問題不大.
          • 但是它依然不是很完美, 存在一些問題不大的問題.(不成問題的問題, 基本一詞基本可用, 但基本不用)

          組合繼承存在什么問題呢?

          • 組合繼承最大的問題就是無論在什么情況下, 都會調用兩次父類構造函數.
          • 一次在創建子類原型的時候
          • 另一次在子類構造函數內部(也就是每次創建子類實例的時候).
          • 另外, 如果你仔細按照我的流程走了上面的每一個步驟, 你會發現: 所有的子類實例事實上會擁有兩份父類的屬性
          • 一份在當前的實例自己里面(也就是person本身的), 另一份在子類對應的原型對象中(也就是person.__proto__里面)
          • 當然, 這兩份屬性我們無需擔心訪問出現問題, 因為默認一定是訪問實例本身這一部分的.

          怎么解決呢?

          • 看起來組合繼承也不是非常完美的解決方案, 雖然也可以應用.
          • 有沒有終極的解決方案呢? 預知后事如何, 且聽下回分解.

          原文來自:https://mp.weixin.qq.com/s?__biz=Mzg5MDAzNzkwNA==&mid=2247483876&idx=1&sn=d9241b9be5462019dbff10fb539e593f&chksm=cfe3f21bf8947b0db29ef6cc5c85acb7d2e60ecc6fb110d897db65af09962a5f34f334c4a4b0&cur_album_id=1566035091556974596&scene=189#wechat_redirect,如有侵權,請聯系刪除;


          主站蜘蛛池模板: 中文字幕无码一区二区三区本日 | 国产精品无码一区二区三区电影| 国产乱人伦精品一区二区| 无码少妇精品一区二区免费动态| 一区在线观看视频| 97精品国产福利一区二区三区| 精品久久国产一区二区三区香蕉| 亚洲成a人一区二区三区| 日本一区二区在线免费观看| 精品视频一区二区三区| 国产精品视频一区二区三区无码| 九九久久99综合一区二区| 亚洲AV日韩综合一区尤物| 成人精品一区二区电影| 国产一区二区三区日韩精品| 伊人激情AV一区二区三区| 国模私拍福利一区二区| 夜夜爽一区二区三区精品| 亚洲国产精品第一区二区| 久久精品国内一区二区三区| 中文字幕一区二区在线播放| 日韩人妻不卡一区二区三区| 国产一区二区在线观看视频| 国产一区二区中文字幕| 国产SUV精品一区二区88L| 香蕉久久一区二区不卡无毒影院| 国产精品亚洲一区二区三区| 国产亚洲3p无码一区二区| 精品国产精品久久一区免费式| 一区二区视频传媒有限公司| 乱精品一区字幕二区| 日韩有码一区二区| 日韩一区二区在线免费观看| 亚洲一区二区三区无码国产| 中文字幕一区二区区免| 亚洲av成人一区二区三区在线观看| 亚洲欧美国产国产一区二区三区| 无码人妻精品一区二区三| 少妇人妻偷人精品一区二区| 一区二区三区免费在线观看| 美女视频一区二区|