国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

繼承與原型

My_Oh_My / 419人閱讀

摘要:既然構(gòu)造函數(shù)有屬于自己的原型對(duì)象,那么我們應(yīng)該能讓另一個(gè)構(gòu)造函數(shù)來(lái)繼承他的原型對(duì)象咯我們?cè)跇?gòu)造函數(shù)內(nèi)部執(zhí)行了函數(shù)并改變了函數(shù)內(nèi)部的指向其實(shí)這個(gè)指向的是實(shí)例化之后的對(duì)象。

我們?cè)谟懀╩ian)論(shi)JavaScript這門語(yǔ)言時(shí),總是繞不過(guò)的一個(gè)話題就是“繼承與原型鏈”。那么“繼承與原型鏈”到底是什么呢?

我很喜歡的一個(gè)聊天模式是:我不能說(shuō)XX是什么,我只能說(shuō)XX像什么。也就是說(shuō)我不直接跟你說(shuō)定義,因?yàn)橥ǔ6裕岸x”所描述的概念很晦澀,比如關(guān)于“閉包”的定義——閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。

所以,我們先來(lái)看一下,JavaScript里到底“繼承與原型鏈”是如何表現(xiàn)的。

“繼承與原型鏈”像什么

不同于Java等的靜態(tài)語(yǔ)言,在JavaScript這門語(yǔ)言里,我們沒(méi)有“類”這個(gè)概念,所有的繼承都是基于原型的。我們先直接看個(gè)例子:

var obj = {
    a: 0,
    f: function() {
        return this.a + 1
    }
}

var obj_1 = {} // 我們期望cat也能有sound屬性跟speak方法

obj_1.__proto__ = obj

console.log(obj_1.a) // 0
console.log(obj_1.f()) // 1

如上,我們定義obj_1這個(gè)對(duì)象的時(shí)候,并沒(méi)有聲明a屬性跟f方法,但是我們依然可以找到它們。這是因?yàn)樵贘avaScript中,你在一個(gè)對(duì)象上尋找某個(gè)屬性(JavaScript對(duì)象都是鍵值對(duì)的形式,所以方法其實(shí)也可以算一個(gè)屬性),他首先會(huì)在該對(duì)象本地尋找,如果沒(méi)有,他會(huì)順著原型鏈一層層往上尋找。

在上面的栗子中,對(duì)象obj_1本地沒(méi)有定義任何屬性,所以當(dāng)我們執(zhí)行obj_1.a的時(shí)候,會(huì)順著原型鏈往上找。在obj_1.__proto__ = obj這句里,我們將obj賦值給了obj_1__proto__屬性。

但是等等,__proto__是什么?

__proto__屬性指向的就是obj_1的原型,obj的原型是什么呢?我們可以打印obj.__proto__來(lái)看看,結(jié)果打印出來(lái)一大堆東西,這些其實(shí)就是Object.prototype,也就是“終極原型”,這個(gè)對(duì)象不再繼承任何原型。按照之前說(shuō)的,obj_1應(yīng)該也能直接訪問(wèn)到這上面的屬性。事實(shí)也的確如此,比如:

obj_1.hasOwnProperty("a") // false

我們并沒(méi)有在obj_1上定義hasOwnProperty方法,但是依然可以找到該方法。事實(shí)上,所有以對(duì)象字面量(Object Literal)形式創(chuàng)建出來(lái)的對(duì)象,都繼承了有Object.prototype上的所有屬性。

那么我們能不能創(chuàng)建一個(gè)不繼承自任何原型的對(duì)象呢?答案是可以的。

JavaScript為我們提供了一個(gè)方法叫Object.create,通過(guò)它,我們可以創(chuàng)建一個(gè)原型為特定對(duì)象的對(duì)象。如果我們傳入一個(gè)null,那么我們就能創(chuàng)建一個(gè)“原型為空”的對(duì)象。

var a = Object.create(null)

在這個(gè)例子里,a成了一個(gè)空的對(duì)象,不僅本地沒(méi)有任何屬性,連原型鏈都沒(méi)有,也就是說(shuō)它甚至都沒(méi)有繼承Object.prototype。(思考:這樣的空對(duì)象到底有什么作用呢?)

這樣一來(lái),我們也可以利用Object.create來(lái)實(shí)現(xiàn)繼承咯?對(duì)的。

var obj = {
    a: 0,
    f: function() {
        return this.a + 1
    }
}

var obj_2 = Object.create(obj)
console.log(obj_2.a) // 0
console.log(obj_2.f()) // 1

但是重新想象,繼承的本質(zhì)是什么?繼承原型!那么不管用什么方法,只要在我的原型鏈上能找到你就行了。

現(xiàn)在有一個(gè)問(wèn)題,obj上定義了一個(gè)屬性a,如果我在obj_2上再定義一個(gè)屬性a,那么打印出來(lái)的會(huì)是誰(shuí)的a呢?

var obj = {
    a: 0,
    f: function() {
        return this.a + 1
    }
}

var obj_2 = Object.create(obj)
obj_2.a = 2
console.log(obj_2.a) // 2

答案是顯而易見的,因?yàn)槲覀冊(cè)趯ふ乙粋€(gè)屬性的時(shí)候,總是從當(dāng)前對(duì)象本地開始的,如果在當(dāng)前對(duì)象上找到了這個(gè)屬性,那么查詢就停止了。所以,如果原型鏈過(guò)長(zhǎng),在查找一個(gè)靠前的原型上的屬性的時(shí)候,就會(huì)比較耗時(shí)。我們應(yīng)當(dāng)盡量避免這種過(guò)長(zhǎng)的原型鏈。

“繼承與原型鏈”是什么

讀到這里,相信我們已經(jīng)能夠?qū)?strong>繼承和原型鏈做一個(gè)定義了。

原型鏈

原型鏈就是從一個(gè)對(duì)象的__proto__開始,一直到這條線的最末端,大部分情況下,這個(gè)最末端就是Object.prototype。例如上面的那個(gè)例子:

var obj = {
    a: 0,
    f: function() {
        return this.a + 1
    }
}

var obj_2 = Object.create(obj)

// obj_2.__proto__ === obj
// obj.__proto__ === Object.prototype
繼承

在這個(gè)例子里,obj --- Object.prototype就組成了一個(gè)原型鏈,順著原型鏈,我們可以找到這個(gè)對(duì)象最開始繼承自哪個(gè)對(duì)象,同時(shí),原型鏈上的每一個(gè)節(jié)點(diǎn)都可以繼承上游對(duì)象的所有屬性。繼承描述的應(yīng)該是一種關(guān)系,或者一種動(dòng)作。

new運(yùn)算符

在前面的篇幅里我們知道,在JavaScript里,對(duì)象可以用字面量的形式與Object.create的形式來(lái)創(chuàng)建。但是JavaScript里還有一種方式來(lái)創(chuàng)建一個(gè)對(duì)象,那就是使用new運(yùn)算符。

var obj = new Object

console.log(obj) // {}

根據(jù)前面的內(nèi)容,我們可知obj繼承了Object.prototype對(duì)象上的屬性。關(guān)于new操作符,可以看我的另一篇專欄當(dāng)我們?cè)贘avaScript中new一個(gè)對(duì)象的時(shí)候,我們到底在做什么。那么Object是什么?

我們來(lái)執(zhí)行一下typeof Object,打印出來(lái)的是"function"。對(duì)的,Object是一個(gè)函數(shù),準(zhǔn)確地說(shuō),它是一個(gè)構(gòu)造函數(shù)。new運(yùn)算符操作的,應(yīng)該是一個(gè)函數(shù)。

我們可以對(duì)任意函數(shù)執(zhí)行new操作。但是一個(gè)函數(shù)如果被用作了構(gòu)造函數(shù)來(lái)實(shí)例化對(duì)象,那我們傾向于把它的首字母大寫。

var Foo = function(x) {
    this.x = x
}

var boo = new Foo(1)
console.log(boo, boo.x) // Foo?{x: 1} 1

構(gòu)造函數(shù)能讓我們初始化一個(gè)對(duì)象,在構(gòu)造函數(shù)里,我們可以做一些初始化的操作。通常我們?cè)诰帉懸恍㎎avaScript插件的時(shí)候會(huì)在全局對(duì)象上掛載一個(gè)構(gòu)造函數(shù),通過(guò)實(shí)例化這個(gè)構(gòu)造函數(shù),我們可以繼承它的原型對(duì)象上的所有屬性。

既然構(gòu)造函數(shù)有屬于自己的原型對(duì)象,那么我們應(yīng)該能讓另一個(gè)構(gòu)造函數(shù)來(lái)繼承他的原型對(duì)象咯?

var Human = function(name) {
    this.name = name
}
var Male = function(name) {
    Human.call(this, name)
    this.gender = "male"
}

var jack = new Male("jack")
console.log(jack) // Male?{name: "jack", gender: "male"}

我們?cè)跇?gòu)造函數(shù)內(nèi)部執(zhí)行了Human函數(shù)并改變了Human函數(shù)內(nèi)部的this指向(其實(shí)這個(gè)this指向的是實(shí)例化之后的對(duì)象)。同時(shí),我們?cè)?b>Male的原型上定義一個(gè)自己的屬性gender,這樣,實(shí)例化出來(lái)的對(duì)象同時(shí)有了兩個(gè)屬性。

但是這個(gè)繼承完整么?繼承是需要繼承原型的,但是jack的原型鏈上并沒(méi)有Human,我們需要額外兩步。

var Human = function(name) {
    this.name = name
}
var Male = function(name) {
    Human.call(this, name)
    this.gender = "male"
}

Male.prototype = Object.create(Human.prototype)
Male.prototype.constructor = Male

var jack = new Male("jack")
console.log(jack) // Male?{name: "jack", gender: "male"}

這樣一來(lái),我們就能在jack的原型鏈上找到Human了。

ES6的類

其實(shí)前面一節(jié)看起來(lái)會(huì)比較晦澀,因?yàn)樵贓S6之前,JavaScript沒(méi)有類的概念(當(dāng)然之后也沒(méi)有),但是我們卻有“構(gòu)造函數(shù)”,那上面一節(jié)的栗子就應(yīng)該說(shuō)是構(gòu)造函數(shù)Male繼承了構(gòu)造函數(shù)Human

我記得當(dāng)時(shí)場(chǎng)面有點(diǎn)尷尬,大家都搓著手低著頭都不知道說(shuō)點(diǎn)兒什么

好在ES6里我們有了Class的關(guān)鍵字,這是個(gè)語(yǔ)法糖,本質(zhì)上,JavaScript的繼承還是基于原型的。但是,至少形式上,我們可以按照“類”的方式來(lái)寫代碼了。

class Human {
    constructor(name) {
        this.name = name
    }
}
class Male extends Human {
    constructor(name) {
        super(name)
        this.gender = "male"
    }
}

var jack = new Male("jack")
console.log(jack) // Male?{name: "jack", gender: "male"}

在控制臺(tái)上順著__proto__一層層往下翻,我們會(huì)能找到class Maleclass Human,這說(shuō)明我們的繼承成功了。同時(shí),我們也可以理解成“類Male繼承了類Human”,雖然在JavaScript其實(shí)并沒(méi)有類這個(gè)東西。

結(jié)語(yǔ)

其實(shí)通篇的核心還是那句話:JavaScript的繼承是基于原型的。很多內(nèi)容我沒(méi)有展開講解很多,表達(dá)了主干即可。

引用

繼承與原型

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107341.html

相關(guān)文章

  • JavaScript系列--淺析原型繼承

    摘要:綜上所述有原型鏈繼承,構(gòu)造函數(shù)繼承經(jīng)典繼承,組合繼承,寄生繼承,寄生組合繼承五種方法,寄生組合式繼承,集寄生式繼承和組合繼承的優(yōu)點(diǎn)于一身是實(shí)現(xiàn)基于類型繼承的最有效方法。 一、前言 繼承是面向?qū)ο螅∣OP)語(yǔ)言中的一個(gè)最為人津津樂(lè)道的概念。許多面對(duì)對(duì)象(OOP)語(yǔ)言都支持兩種繼承方式::接口繼承 和 實(shí)現(xiàn)繼承 。 接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。由于js中方法沒(méi)有簽名...

    draveness 評(píng)論0 收藏0
  • 創(chuàng)建對(duì)象(一):創(chuàng)建繼承

    摘要:創(chuàng)建實(shí)例的方式有三種對(duì)象字面量表示法操作符跟構(gòu)造函數(shù)中的函數(shù)。下面主要講的是最為復(fù)雜的操作符跟構(gòu)造函數(shù)的創(chuàng)建對(duì)象實(shí)例的方法。 創(chuàng)建對(duì)象 一.創(chuàng)建對(duì)象的方法 理解原型對(duì)象: 無(wú)論什么時(shí)候,只要?jiǎng)?chuàng)建了新函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè) prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。在默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè)constructor屬性,這個(gè)屬性包含一個(gè)指向p...

    microelec 評(píng)論0 收藏0
  • JavaScript 的繼承方式及優(yōu)缺點(diǎn)

    摘要:繼承簡(jiǎn)介在的中的面向?qū)ο缶幊蹋^承是給構(gòu)造函數(shù)之間建立關(guān)系非常重要的方式,根據(jù)原型鏈的特點(diǎn),其實(shí)繼承就是更改原本默認(rèn)的原型鏈,形成新的原型鏈的過(guò)程。 showImg(https://segmentfault.com/img/remote/1460000018998684); 閱讀原文 前言 JavaScript 原本不是純粹的 OOP 語(yǔ)言,因?yàn)樵?ES5 規(guī)范中沒(méi)有類的概念,在 ...

    nanchen2251 評(píng)論0 收藏0
  • JS學(xué)習(xí)筆記(第6章)(面向?qū)ο笾?em>繼承——JS繼承的六大方式)

    摘要:除此之外,在超類型的原型中定義的方法,對(duì)子類型而言也是不可兼得,結(jié)果所有類型都只能用構(gòu)造函數(shù)模式。創(chuàng)建對(duì)象增強(qiáng)對(duì)象指定對(duì)象繼承屬性這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次構(gòu)造函數(shù)。 1、原型鏈 原型鏈的基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象;原型對(duì)象都包含著一個(gè)指向構(gòu)造函數(shù)的指針;實(shí)例都包含一個(gè)指向原型對(duì)象的...

    lscho 評(píng)論0 收藏0
  • 前端進(jìn)擊的巨人(七):走進(jìn)面向?qū)ο螅?em>原型原型鏈,繼承方式

    摘要:除了以上介紹的幾種對(duì)象創(chuàng)建方式,此外還有寄生構(gòu)造函數(shù)模式穩(wěn)妥構(gòu)造函數(shù)模式。 showImg(https://segmentfault.com/img/remote/1460000018196128); 面向?qū)ο?是以 對(duì)象 為中心的編程思想,它的思維方式是構(gòu)造。 面向?qū)ο?編程的三大特點(diǎn):封裝、繼承、多態(tài): 封裝:屬性方法的抽象 繼承:一個(gè)類繼承(復(fù)制)另一個(gè)類的屬性/方法 多態(tài):方...

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

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

0條評(píng)論

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