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

資訊專欄INFORMATION COLUMN

通過(guò)類型繼承深入理解原型繼承

Hegel_Gu / 988人閱讀

摘要:上圖中的在原型繼承稱作構(gòu)造器。構(gòu)造器就是一個(gè)普通的函數(shù),但是將操作符用到構(gòu)造器上時(shí),它會(huì)執(zhí)行一個(gè)叫的過(guò)程。從第條可以看到,構(gòu)造器生成的對(duì)象的屬性會(huì)指向構(gòu)造器的值,這就是我們構(gòu)造原型鏈的關(guān)鍵。

基于類的繼承是大多數(shù)人所熟悉的,也是比較容易理解的。當(dāng)我們形成類型繼承的思維定勢(shì)后,再次接觸原型繼承可能會(huì)覺(jué)得有些奇怪并難以理解。你更可能會(huì)吐槽,原型繼承根本就不能叫做繼承,一點(diǎn)都不面向?qū)ο蟆1救俗畛跻彩沁@樣認(rèn)為的,但深入仔細(xì)的對(duì)比后發(fā)現(xiàn),兩者其實(shí)并沒(méi)有本質(zhì)的差別,只是表面有點(diǎn)不一樣而已。且看下面的分析。

類型繼承

先看一個(gè)類型繼承的例子,代碼如下:

public class A {
    //...
}

public class B extends A {
    //...
}

public class C extends B {
    //...
}

C c = new C();

A、B、C為三個(gè)繼承關(guān)系的類,最后將類C實(shí)例化。下面這張圖描述了類和實(shí)例的對(duì)應(yīng)關(guān)系。左邊為類,右邊為其對(duì)應(yīng)實(shí)例。

我們看到,類C實(shí)例化后,內(nèi)存中不僅存在c對(duì)象,同時(shí)還有a、b兩個(gè)對(duì)象。因?yàn)樵趈ava中,當(dāng)我們?cè)趫?zhí)行new C()操作時(shí),jvm中會(huì)發(fā)生如下過(guò)程:

創(chuàng)建A的實(shí)例a。

創(chuàng)建B的實(shí)例b,并將實(shí)例b的super指針指向a。

創(chuàng)建C的實(shí)例c,并將實(shí)例c的super指針指向b。

過(guò)程1和過(guò)程2對(duì)用戶是透明的,不需要人工干預(yù),引擎會(huì)按照“藍(lán)圖”把這兩個(gè)過(guò)程完成。通過(guò)上圖右半部分我們可以看到,super指針將a、b、c三個(gè)實(shí)例串起來(lái)了,這里是實(shí)現(xiàn)繼承的關(guān)鍵。當(dāng)我們?cè)谑褂脤?shí)例c的某個(gè)屬性或方法時(shí),若實(shí)例c中不存在則會(huì)沿著super指針向父類對(duì)象查找,直到找到,找不到則出錯(cuò)。這就是繼承能夠達(dá)到復(fù)用目的內(nèi)部機(jī)制??吹竭@里大家或許已經(jīng)聯(lián)想到原型鏈了,super所串起來(lái)的這個(gè)鏈幾乎和原型鏈一樣,只是叫法不一樣而已。下面我們就來(lái)看看原型繼承。

原型繼承

上面是原型繼承的示意圖。先看圖的右半部分,__proto__指針形成的對(duì)象鏈就是原型鏈。__proto__是一個(gè)私有屬性,只能看不準(zhǔn)訪問(wèn)(某些瀏覽器看也不給看)。__proto__的作用和前面的super是一樣的,原型鏈實(shí)現(xiàn)復(fù)用的機(jī)制和類型繼承也幾乎是一樣的,這里不再重復(fù)。有一點(diǎn)不一樣就是原型繼承中的屬性寫操作只會(huì)改變當(dāng)前對(duì)象并不會(huì)影響原型鏈上的對(duì)象。

如何去構(gòu)造原型鏈呢?看上去要稍微麻煩一些。原型繼承里面沒(méi)有類的概念,我們需要通過(guò)代碼,手動(dòng)完成這個(gè)過(guò)程。上圖中的A、B、C在原型繼承稱作構(gòu)造器。構(gòu)造器就是一個(gè)普通的函數(shù),但是將new操作符用到構(gòu)造器上時(shí),它會(huì)執(zhí)行一個(gè)叫[[construct]]的過(guò)程。大致如下:

創(chuàng)建一個(gè)空對(duì)象obj。

設(shè)置obj的內(nèi)部屬性[[Class]]為Object。

設(shè)置obj的內(nèi)部屬性[[Extensible]]為true。

設(shè)置obj的[[__proto__]]屬性:如果函數(shù)對(duì)象prototype的值為對(duì)象則直接賦給obj,否則賦予Object的prototype值。

調(diào)用函數(shù)對(duì)象的[[Call]]方法并將結(jié)果賦給result。

如果result為對(duì)象則返回result,否則返回obj。

從第4條可以看到,構(gòu)造器生成的對(duì)象的__proto__屬性會(huì)指向構(gòu)造器的prototype值,這就是我們構(gòu)造原型鏈的關(guān)鍵。下面的代碼是上圖原型鏈的構(gòu)造過(guò)程。

function A(){
    //...
}

function B(){
    //...
}

function C(){
    //...
}

var a = new A();
B.prototype = a;
var b = new B();
C.prototype = b;
var c = new C();

上述代碼雖然能達(dá)到目的,但有點(diǎn)繁瑣,我們可以將這個(gè)過(guò)程封裝一下。backbone的實(shí)現(xiàn)是這樣的:

var extend = function(protoProps, staticProps) {
    var parent = this;
    var child;
    if (protoProps && _.has(protoProps, "constructor")) {
      child = protoProps.constructor;
    } else {
      child = function(){ return parent.apply(this, arguments); };
    }    
    _.extend(child, parent, staticProps);
    child.prototype = _.create(parent.prototype, protoProps);
    child.prototype.constructor = child;
    child.__super__ = parent.prototype;
    return child;
  }

其中_.extend(child, parent, staticProps)是將staticProps和parent對(duì)象的屬性復(fù)制給child。_.create方法的實(shí)現(xiàn)大概如下。

_.create = function(prototype, protoProps){
    var F = function(){};
    F.prototype = prototype;
    var result = new F();
    return _.extend(result, protoProps);
}

有了extend方法,我們的代碼就可以寫成:

    A.extend = extend;
    var B = A.extend({
        //...
    );
    var C = B.extend({
        //...
    );
    var c = new C();

這段代碼和類型繼承的代碼十分相似,通過(guò)原型繼承我們也可以達(dá)到類型繼承的效果。但是通過(guò)前面的比較我們發(fā)現(xiàn),繼承的本質(zhì)就其實(shí)就是對(duì)象的復(fù)用。原型繼承本身就是以對(duì)象為出發(fā)點(diǎn)考慮的,所以大多時(shí)候我們并不一定要按照類型繼承的思維考慮問(wèn)題。而且js是弱類型,對(duì)象的操作也極其自由,上述的_.create方法可能是js里面實(shí)現(xiàn)繼承的一個(gè)更簡(jiǎn)單有效的方法。

總結(jié)

前面討論了兩種繼承方式,可以看到,繼承的本質(zhì)其實(shí)就是對(duì)象的復(fù)用。本人覺(jué)得原型繼承更加的簡(jiǎn)單和明確,它直接就是從對(duì)象的角度考慮問(wèn)題。當(dāng)然,如果你需要一個(gè)非常強(qiáng)大的繼承體系,你也可以構(gòu)造出一個(gè)類似類型繼承的模式。相對(duì)來(lái)說(shuō),本人覺(jué)得原型繼承更靈活和自由些,也是非常巧妙和獨(dú)特的。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/64688.html

相關(guān)文章

  • 通過(guò)類型繼承深入理解原型繼承

    摘要:上圖中的在原型繼承稱作構(gòu)造器。構(gòu)造器就是一個(gè)普通的函數(shù),但是將操作符用到構(gòu)造器上時(shí),它會(huì)執(zhí)行一個(gè)叫的過(guò)程。從第條可以看到,構(gòu)造器生成的對(duì)象的屬性會(huì)指向構(gòu)造器的值,這就是我們構(gòu)造原型鏈的關(guān)鍵。 基于類的繼承是大多數(shù)人所熟悉的,也是比較容易理解的。當(dāng)我們形成類型繼承的思維定勢(shì)后,再次接觸原型繼承可能會(huì)覺(jué)得有些奇怪并難以理解。你更可能會(huì)吐槽,原型繼承根本就不能叫做繼承,一點(diǎn)都不面向?qū)ο蟆1救?..

    Alliot 評(píng)論0 收藏0
  • JavaScript之深入各種繼承

    摘要:通常有這兩種繼承方式接口繼承和實(shí)現(xiàn)繼承。理解繼承的工作是通過(guò)調(diào)用函數(shù)實(shí)現(xiàn)的,所以是寄生,將繼承工作寄托給別人做,自己只是做增強(qiáng)工作。適用基于某個(gè)對(duì)象或某些信息來(lái)創(chuàng)建對(duì)象,而不考慮自定義類型和構(gòu)造函數(shù)。 一、繼承的概念 繼承,是面向?qū)ο笳Z(yǔ)言的一個(gè)重要概念。通常有這兩種繼承方式:接口繼承和實(shí)現(xiàn)繼承。接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。 《JS高程》里提到:由于函數(shù)沒(méi)有簽名,...

    tomlingtm 評(píng)論0 收藏0
  • 深入理解Javascript原型關(guān)系

    摘要:如下所示在規(guī)范中,已經(jīng)正式把屬性添加到規(guī)范中也可以通過(guò)設(shè)置和獲取對(duì)象的原型對(duì)象對(duì)象之間的關(guān)系可以用下圖來(lái)表示但規(guī)范主要介紹了如何利用構(gòu)造函數(shù)去構(gòu)建原型關(guān)系。 前言 在軟件工程中,代碼重用的模式極為重要,因?yàn)樗麄兛梢燥@著地減少軟件開(kāi)發(fā)的成本。在那些主流的基于類的語(yǔ)言(比如Java,C++)中都是通過(guò)繼承(extend)來(lái)實(shí)現(xiàn)代碼復(fù)用,同時(shí)類繼承引入了一套類型規(guī)范。而JavaScript是...

    ethernet 評(píng)論0 收藏0
  • 深入理解JavaScript

    摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對(duì)于解釋型語(yǔ)言例如來(lái)說(shuō),通過(guò)詞法分析語(yǔ)法分析語(yǔ)法樹(shù),就可以開(kāi)始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評(píng)論0 收藏0
  • 深入理解 JavaScript 中的 class

    摘要:在規(guī)范中,引入了的概念。使用中的聲明一個(gè)類,是非常簡(jiǎn)單的事。中面向?qū)ο髮?shí)例化的背后原理,實(shí)際上就是原型對(duì)象。與區(qū)別理解上述原理后,還需要注意與屬性的區(qū)別。實(shí)際上,在中,類繼承的本質(zhì)依舊是原型對(duì)象。 在 ES6 規(guī)范中,引入了 class 的概念。使得 JS 開(kāi)發(fā)者終于告別了,直接使用原型對(duì)象模仿面向?qū)ο笾械念惡皖惱^承時(shí)代。 但是JS 中并沒(méi)有一個(gè)真正的 class 原始類型, clas...

    Vicky 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<