亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

詳解js中的繼承(一)

Object / 2539人閱讀

摘要:構造函數,實例構造函數,是用來創(chuàng)建對象的函數,本質上也是函數。這里剛好解釋一下時,說到的,可以通過實例的訪問構造函數,但是本質上是原型對象的屬性。

前言

最近在學vue,到周末終于有空寫一些東西了(想想又能騙贊,就有點小激動?。?。在javascript基礎中,除了閉包之外,繼承也是一個難點。因為考慮到篇幅較長,所以打算分成兩個部分來寫。同樣基于《javascript高級程序設計》,做一個詳細的講解,如果有不對的地方歡迎指正。

準備知識

為了更好的講解繼承,先把一些準備知識放在前面。

1.構造函數,實例

構造函數,是用來創(chuàng)建對象的函數,本質上也是函數。與其他函數的區(qū)別在于調用方式不同:

如果通過new操作符來調用的,就是構造函數

如果沒有通過new操作符來調用的,就是普通函數
例子:

function Person(name, age) {
   this.name = name;
   this.age = age;
 }
 //當做構造函數調用
 var person1 = new Person("Mike",10);
 
 //當做普通函數調用,這里相當于給window對象添加了name和age屬性,這個不是重點,只要注意調用方式
 Person("Bob",12);
 
 console.log(person1)//Person {name: "Mike", age: 10}
 console.log(name)//Bob
 console.log(age)//12

var person1 = new Person("Mike",10);中,通過new操作符調用了函數Person,并且生成了person1,
這里的Person就稱為構造函數,person1稱為Person函數對象的一個實例。實可以通過實例的constructor訪問對應的構造函數(但是其實上這個constructor不是實例的屬性,后面會解釋為什么),看下面的例子:

 function Person(name, age) {
    this.name = name;
    this.age = age;
  }
 var person1 = new Person("Mike",10);
 var person2 = new Person("Alice",20);
 console.log(person1.constructor)//function Person(){省略內容...}
 console.log(person2.constructor)//function Person(){省略內容...}
2.原型對象

當我們每次創(chuàng)建一個函數的時候,函數對象都會有一個prototype屬性,這個屬性是一個指針,指向它的原型對象原型對象的本質也是一個對象。初次看這句話可能有點難以理解,舉個例子,還是剛剛那個函數:

     function Person(name, age) {
        this.name = name;
        this.age = age;
     }
     console.log(Person.prototype)//object{constructor:Person}

可以看到Person.prototype指向了一個對象,即Person的原型對象,并且這個對象有一個constructor屬性,又指向了Person函數對象。是不是有點暈?沒關系,接下來我們就上比舉例子更好的手段--畫圖。

3.構造函數,原型對象和實例的關系

在前面,我們剛剛介紹過了構造函數,實例和原型對象,接下來我們用一張圖來表示這三者之間的關系(用ps畫這種圖真是麻煩的要死,大家有好的工具推薦一下):

從圖上我們可以看到:

函數對象的prototype指向原型對象,原型對象的constructor指向函數對象

實例對象的[Protoptype]屬性指向原型對象,這里的[Protoptype]內部屬性,可以先理解為它是存在的,但是不允許我們訪問(雖然在有些瀏覽器是允許訪問這個屬性的,但是我們先這樣理解),這個屬性的作用是:允許實例通過該屬性訪問原型對象中的屬性和方法。比如說:

    function Person(name, age) {
        this.name = name;
        this.age = age;
      }
      //在原型對象中添加屬性或者方法
     Person.prototype.sex = "男"; 
     var person1 = new Person("Mike",10);
     var person2 = new Person("Alice",20);
     //只給person2設置性別
     person2.sex = "女";
     console.log(person1.sex)//"男"
     console.log(person2.sex)//"女"

這里我們沒有給person1實例設置sex屬性,但是因為[Protoptype]的存在,會訪問原型對象中對應的屬性;
同時我們給person2設置sex屬性后輸出的是"女",說明只有當實例本身不存在對應的屬性或方法時,才會去找原型對象上的對應屬性或方法

補充一下:ECMA-262第五版的時候這個內部屬性叫[Prototype],而_proto_Firefox,Chrome和Safari瀏覽器提供的一個屬性,在其他的實現里面,這個內部屬性是沒法訪問的。所以我們能從控制臺看到的是_proto_屬性,但是我在文中用的還是[Prototype],個人認為這樣較符合它的本質。

tips:這里剛好解釋一下console.log(person1.constructor)時,說到的,可以通過實例的constructor訪問構造函數,但是constructor本質上是原型對象的屬性。

繼承 原型鏈

在js中,繼承的主要思路就是利用原型鏈,因此如果理解了原型鏈,繼承問題就理解了一半。在這里可以稍微休息一下,如果對前面的準備知識已經理解差不多了,就開始講原型鏈了。

原型鏈的原理是:讓一個引用類型繼承另一個引用類型的屬性和方法。
先回顧一下剛剛講過的知識:

原型對象通過constructor屬性指向構造函數

實例通過[Prototype]屬性指向原型對象

那現在我們來思考一個問題:如果讓原型對象等于另一個構造函數的實例會怎么樣?
例如:

    function A() {
     
    }
    //在A的原型上綁定sayA()方法
    A.prototype.sayA = function(){
            console.log("from A")
    }
    function B(){

    }
    
     //讓B的原型對象指向A的一個實例
     B.prototype = new A();
     
     //在B的原型上綁定sayB()方法
     B.prototype.sayB = function(){
            console.log("from B")
     }
     //生成一個B的實例
     var a1 = new A();
     var b1 = new B();
     
     //b1可以調用sayB和sayA
     b1.sayB();//"from B"
     b1.sayA();//"from A"

為了方便理解剛剛發(fā)生了什么,我們再上一張圖:

現在結合圖片來看代碼:

首先,我們創(chuàng)建了A和B兩個函數對象,同時也就生成了它們的原型對象

接著,我們給A的原型對象添加了sayA()方法
* 然后是關鍵性的一步B.prototype = new A();,我們讓函數對象B的protytype指針指向了一個A的實例,請注意我的描述:是讓函數對象B的protytype指針指向了一個A的實例,這也是為什么最后,B的原型對象里面不再有constructor屬性,其實B本來有一個真正的原型對象,原本可以通過B.prototype訪問,但是我們現在改寫了這個指針,使它指向了另一個對象,所以B真正的原型對象現在沒法被訪問了,取而代之的這個新的原型對象是A的一個實例,自然就沒有constructor屬性了

接下來我們給這個B.prototype指向的對象,增加一個sayB方法

然后,我們生成了一個實例b1

最后我們調用了b1的sayB方法,可以執(zhí)行,為什么?
因為b1有[Prototype]屬性可以訪問B prototype里面的方法;

我們調用了b1的sayA方法,可以執(zhí)行,為什么?
因為b1沿著[Prototype]屬性可以訪問B prototype,B prototype繼續(xù)沿著[Prototype]屬性訪問A prototype,最終在A.prototype上找到了sayA()方法,所以可以執(zhí)行

所以,現在的結果就相當于,b1繼承了A的屬性和方法,這種[Prototype]不斷把實例和原型對象聯(lián)系起來的結構就是原型鏈。也是js中,繼承主要的實現方式。

小結

因為這部分知識理解起來比較難,所以第一部分先寫到這里(當然不是因為我想多寫一篇來騙贊和關注啦),大家讀到這里也可以歇口氣了,如果這一塊理解深刻,下一部分就會很輕松。
為了測試一下大家對于本文的理解程度,問一下幾個問題:

在最后一個例子里,console.log(b1.constructor),結果是什么?

B.prototype = new A(); B.prototype.sayB = function(){ console.log("from B") }這兩句的執(zhí)行順序能不能交換

最后再思考一下. 在最后一個例子里,A看似已經是原型鏈的最頂層,那A還能再往上嗎?

以上答案在下篇中解答,讀者可以自己先試試,思考一下,有疑問也可以在評論中提出。最后,如果這篇文章對你有幫助,請大方的點收藏和推薦吧(每次都是收藏比推薦多!,組織語言,畫圖和排版都很辛苦的),你們的支持會給我更大的動力~以上內容屬于個人見解,如果有不同意見,歡迎指出和探討。請尊重作者的版權,轉載請注明出處,如作商用,請與作者聯(lián)系,感謝!

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://www.ezyhdfw.cn/yun/82081.html

相關文章

  • js 中的 call / apply 方法詳解和引用類型的繼承

    摘要:也就是說當使用后,當前執(zhí)行上下文中的對象已被替換為,后續(xù)執(zhí)行將以所持有的狀態(tài)屬性繼續(xù)執(zhí)行。借用的方法替換的實例去調用相應的方法。實現引用類型的繼承其實沒有類這一概念,我們平時使用的等嚴格來說被稱作引用類型。 call 方法:object.method.call(targetObj[, argv1, argv2, .....]) apply 方法:object.method.apply(...

    cod7ce 評論0 收藏0
  • javaScript原型及原型鏈詳解(二)

    摘要:當然這還沒完,因為我們還有重要的一步沒完成,沒錯就是上面的第行代碼,如果沒有這行代碼實例中的指針是指向構造函數的,這樣顯然是不對的,因為正常情況下應該指向它的構造函數,因此我們需要手動更改使重新指向對象。 第一節(jié)內容:javaScript原型及原型鏈詳解(二) 第一節(jié)中我們介紹了javascript中的原型和原型鏈,這一節(jié)我們來講利用原型和原型鏈我們可以做些什么。 普通對象的繼承 ...

    widuu 評論0 收藏0
  • JavaScript深入淺出

    摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統(tǒng)的類繼承還要強大。中文指南基本操作指南二繼續(xù)熟悉的幾對方法,包括,,。商業(yè)轉載請聯(lián)系作者獲得授權,非商業(yè)轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家?guī)韼椭?...(據說是阿里的前端妹子寫的) this 的值到底...

    blair 評論0 收藏0
  • JavaScript繼承方式詳解

    摘要:可以通過構造函數和原型的方式模擬實現類的功能。原型式繼承與類式繼承類式繼承是在子類型構造函數的內部調用超類型的構造函數。寄生式繼承這種繼承方式是把原型式工廠模式結合起來,目的是為了封裝創(chuàng)建的過程。 js繼承的概念 js里常用的如下兩種繼承方式: 原型鏈繼承(對象間的繼承) 類式繼承(構造函數間的繼承) 由于js不像java那樣是真正面向對象的語言,js是基于對象的,它沒有類的概念。...

    Yangyang 評論0 收藏0
  • 前端文檔收集

    摘要:系列種優(yōu)化頁面加載速度的方法隨筆分類中個最重要的技術點常用整理網頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數組函數數據訪問性能優(yōu)化方案實現的大排序算法一怪對象常用方法函數收集數組的操作面向對象和原型繼承中關鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術點 常用meta整理 網頁性能管理詳解 HTML5 ...

    jsbintask 評論0 收藏0

發(fā)表評論

0條評論

Object

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<