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

資訊專欄INFORMATION COLUMN

深入理解Javascript原型關(guān)系

ethernet / 2749人閱讀

摘要:如下所示在規(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是一門(mén)弱類型的語(yǔ)言,從來(lái)不需要類型裝換,在JavaScript中變量可以指向任何類型的value(ES6規(guī)范中的類也只是語(yǔ)法糖,基于類的繼承本質(zhì)上也是通過(guò)原型實(shí)現(xiàn))。而基于原型的繼承模式可以說(shuō)提供了更加豐富的代碼重用模式(后面再詳細(xì)講解JavaScript中的常用繼承模式,本文只專注于JavaScript中的原型),一個(gè)對(duì)象可以直接繼承另外一個(gè)對(duì)象,從而獲得新的方法和屬性。

適合人群

對(duì)JavaScript原型有一定了解,希望深入了解原型。

具有JavaScript相關(guān)開(kāi)發(fā)經(jīng)驗(yàn)

不適合剛接觸JavaScript人員

對(duì)象

要理解JavaScript中的原型關(guān)系,首先必須弄清楚對(duì)象的基本概念。ECMAScript 5.1規(guī)范中描述的對(duì)象

An object is a collection of properties and has a single prototype object. The prototype may be the null value.

直譯就是:對(duì)象是屬性的集合并且擁有一個(gè)原型對(duì)象。原型可能是null(除非故意設(shè)置一個(gè)對(duì)象的原型為null,否則只有Object.prototype的原型為null)。我們可以簡(jiǎn)單把對(duì)象想象成hash表。有一種說(shuō)法是JavaScript中一切都是對(duì)象,這種說(shuō)法并不準(zhǔn)確。How is almost everything in Javascript an object?

原型
JavaScript的原型存在著諸多矛盾。它的某些復(fù)雜的語(yǔ)法看起來(lái)就像那些基于類的語(yǔ)言,這些語(yǔ)法的問(wèn)題掩蓋了它的原型機(jī)制。它不直接讓對(duì)象從其他對(duì)象繼承,反而插入一個(gè)多余的間接層:通過(guò)構(gòu)建器函數(shù)產(chǎn)生對(duì)象。——JavaScript語(yǔ)言精粹第5章節(jié)(繼承)

雖然可以直接設(shè)置一個(gè)對(duì)象的原型為另外一個(gè)對(duì)象,從而獲得新的方法和屬性。如下所示:

// Generic prototype for all letters.
let letter = {
  getNumber() {
    return this.number
  }
}

// 在ES6規(guī)范中,已經(jīng)正式把__proto__屬性添加到規(guī)范中
// 也可以通過(guò)Object.setPrototypeOf(obj, prototype) Object.getPrototypeOf(obj)
// 設(shè)置和獲取對(duì)象的原型對(duì)象

let a = { number: 1, __proto__: letter }
let b = { number: 2, __proto__: letter }
// ...
let z = { number: 26, __proto__: letter }

console.log(
  a.getNumber(), // 1
  b.getNumber(), // 2
  z.getNumber() // 26
)

對(duì)象之間的關(guān)系可以用下圖來(lái)表示

但規(guī)范主要介紹了如何利用構(gòu)造函數(shù)去構(gòu)建原型關(guān)系。所以JavaScript語(yǔ)言精粹的作者Douglas Crockford才會(huì)認(rèn)為:不讓對(duì)象直接繼承另外一個(gè)對(duì)象,而通過(guò)中間層(構(gòu)造函數(shù))去實(shí)現(xiàn)顯得有些復(fù)雜而且存在一些弊端。調(diào)用構(gòu)造器函數(shù)忘記new關(guān)鍵字,this將不會(huì)綁定到一個(gè)新對(duì)象上。悲劇的是,this將會(huì)綁定到全局對(duì)象上。詳情可以閱讀JavaScript語(yǔ)言精粹繼承章節(jié)。

下面利用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)上述同樣功能

function Letter(number) {
  this.number = number
}

Letter.prototype.getNumber = function() {
  return this.number
}

let a = new Letter(1)
let b = new Letter(2)
let z = new Letter(26)

console.log(
  a.getNumber(), // 1
  b.getNumber(), // 2
  z.getNumber() // 26
)

其中原型關(guān)系可以下圖表示

prototype__proto__屬性

我們看下規(guī)范中有關(guān)原型介紹的核心,更多詳情請(qǐng)閱讀ECMAScript 5.1 4.2.1章節(jié)

...Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties...

Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain...

通過(guò)上面的描述我們可以得出以下結(jié)論

構(gòu)造函數(shù)就是一個(gè)函數(shù),函數(shù)中包含prototype屬性用來(lái)實(shí)現(xiàn)基于原型的繼承和共享屬性。通過(guò)Function.prototype.bind方法構(gòu)造出來(lái)的函數(shù)是個(gè)例外,它沒(méi)有prototype屬性。

通過(guò)被構(gòu)造函數(shù)創(chuàng)建的對(duì)象都有一個(gè)隱式的引用指向構(gòu)造函數(shù)的prototype屬性。

構(gòu)造函數(shù)的prototype屬性值同樣也是普通一個(gè)對(duì)象,它也有一個(gè)隱式的引用(non-null)指向它的原型對(duì)象。這樣才形成了原型鏈,所以通過(guò)原型鏈去查找屬性值時(shí)候,并不會(huì)訪問(wèn)prototype屬性,而是obj.__proto__.__proto__...這樣一層一層去尋找。

構(gòu)造函數(shù)說(shuō)到底本質(zhì)上也是一個(gè)普通函數(shù),只是該函數(shù)專門(mén)通過(guò)new關(guān)鍵字來(lái)生成對(duì)象。所以JavaScript語(yǔ)言無(wú)法確定哪個(gè)函數(shù)是打算用來(lái)做構(gòu)造函數(shù)的。所以每個(gè)函數(shù)都會(huì)得到一個(gè)prototype屬性,該屬性值是一個(gè)包含constructor屬性且constructor屬性值為該函數(shù)的對(duì)象,如下所示。

只有函數(shù)才擁有prototype屬性用來(lái)實(shí)現(xiàn)原型的繼承,其他對(duì)象并沒(méi)有。對(duì)象擁有__proto__指向其原型對(duì)象,JavaScript引擎可通過(guò)內(nèi)部屬性[[prptotype]]獲取對(duì)象的原型對(duì)象。

關(guān)于這兩個(gè)屬性聯(lián)系可以用一句話概括:__proto__ is the actual object that is used in the prototype chain to resolve field,methods, etc. prototype is the object that is used to build __proto__ when you create an object with new.

為什么要設(shè)計(jì)構(gòu)造函數(shù)

如果你已經(jīng)了解JavaScript原型,那我們可以來(lái)講講JavaScript語(yǔ)法為什么要設(shè)計(jì)構(gòu)造函數(shù)。

首先來(lái)加深一遍概念:JavaScript是一門(mén)基于原型繼承的語(yǔ)言,這意味著對(duì)象可以直接從其他對(duì)象繼承屬性,該語(yǔ)言是無(wú)類型的。
然而這種設(shè)計(jì)是偏離主流方向的,當(dāng)時(shí)主流語(yǔ)言JavaScript,C++都是通過(guò) new Class 的語(yǔ)法來(lái)創(chuàng)建對(duì)象。JavaScript顯然對(duì)它的原型本質(zhì)缺乏信心,所以它提供了一套和class語(yǔ)法類似的對(duì)象構(gòu)建語(yǔ)法——也就是構(gòu)造函數(shù)。通過(guò)instanceof操作符來(lái)判斷對(duì)象是否屬于某一類型。

instanceof 操作符

MDN介紹了其內(nèi)部原理

The instanceof operator tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object.

instanceof操作符的語(yǔ)法

object instanceof constructor

簡(jiǎn)單來(lái)說(shuō):instanceof 操作符就是判斷構(gòu)造函數(shù)的prototype屬性值是否能在object對(duì)象的原型鏈中被找到,對(duì)就是這么簡(jiǎn)單。這樣通過(guò)構(gòu)造函數(shù)語(yǔ)法JavaScript引入了類的概念(偽類)。

最后的彩蛋

知乎用戶wang z在其專欄中發(fā)布一張有關(guān)JavaScript原型鏈圖,可以說(shuō)看懂了圖片也就清楚了JavaScript中的原型關(guān)系,感興趣的用戶可以直接瀏覽詳情。如下圖所示

筆者就可能讀者遇到的問(wèn)題備注如下:

Object.__proto__=== Function.prototype。Object本質(zhì)上是一個(gè)built-in的全局構(gòu)造函數(shù),也是Function構(gòu)造函數(shù)的實(shí)例。所以O(shè)bject.__proto__ === Function.prototype.

Number,Date,Array等built-in構(gòu)造函數(shù)都和Object構(gòu)造函數(shù)一樣。

Function.prototype本質(zhì)也是對(duì)象,所以其__proto__指向Object.prototype

最后

如果你最后還是沒(méi)有弄清楚JavaScript中的原型關(guān)系,可以在評(píng)論中進(jìn)行描述我將盡我所能幫你答疑解惑。
或許你也可以看看參考文獻(xiàn)中的引用鏈接。

參考文獻(xiàn)

JavaScript. The Core: 2nd Edition

ecma-262

JavaScript Prototype in Plain Language

proto VS. prototype in JavaScript

Javascript語(yǔ)言精粹第五章節(jié)

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

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

相關(guān)文章

  • 深入學(xué)習(xí)js之——原型原型

    摘要:我們用一張圖表示構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系好了構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系我們已經(jīng)梳理清楚了,那我們?cè)趺幢硎緦?shí)例與實(shí)例原型,也就是或者和之間的關(guān)系呢。 開(kāi)篇: 在Brendan Eich大神為JavaScript設(shè)計(jì)面向?qū)ο笙到y(tǒng)的時(shí)候,借鑒了Self 和Smalltalk這兩門(mén)基于原型的語(yǔ)言,之所以選擇基于原型的面向?qū)ο笙到y(tǒng),并不是因?yàn)闀r(shí)間匆忙,它設(shè)計(jì)起來(lái)相對(duì)簡(jiǎn)單,而是因?yàn)閺囊婚_(kāi)始B...

    FingerLiu 評(píng)論0 收藏0
  • 深入學(xué)習(xí)js之——原型原型

    摘要:我們用一張圖表示構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系好了構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系我們已經(jīng)梳理清楚了,那我們?cè)趺幢硎緦?shí)例與實(shí)例原型,也就是或者和之間的關(guān)系呢。 開(kāi)篇: 在Brendan Eich大神為JavaScript設(shè)計(jì)面向?qū)ο笙到y(tǒng)的時(shí)候,借鑒了Self 和Smalltalk這兩門(mén)基于原型的語(yǔ)言,之所以選擇基于原型的面向?qū)ο笙到y(tǒng),并不是因?yàn)闀r(shí)間匆忙,它設(shè)計(jì)起來(lái)相對(duì)簡(jiǎn)單,而是因?yàn)閺囊婚_(kāi)始B...

    xialong 評(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)。 寫(xiě)在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評(píng)論0 收藏0
  • JavaScript深入之從原型原型

    摘要:深入系列的第一篇,從原型與原型鏈開(kāi)始講起,如果你想知道構(gòu)造函數(shù)的實(shí)例的原型,原型的原型,原型的原型的原型是什么,就來(lái)看看這篇文章吧。讓我們用一張圖表示構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系在這張圖中我們用表示實(shí)例原型。 JavaScript深入系列的第一篇,從原型與原型鏈開(kāi)始講起,如果你想知道構(gòu)造函數(shù)的實(shí)例的原型,原型的原型,原型的原型的原型是什么,就來(lái)看看這篇文章吧。 構(gòu)造函數(shù)創(chuàng)建對(duì)象 我們先...

    Songlcy 評(píng)論0 收藏0
  • 【5】JavaScript 函數(shù)高級(jí)——原型原型深入理解(圖解)

    摘要:探索是如何判斷的表達(dá)式如果函數(shù)的顯式原型對(duì)象在對(duì)象的隱式原型鏈上,返回,否則返回是通過(guò)自己產(chǎn)生的實(shí)例案例案例重要注意的顯示原型和隱式原型是一樣的。面試題測(cè)試題測(cè)試題報(bào)錯(cuò)對(duì)照下圖理解 原型與原型鏈深入理解(圖解) 原型(prototype) 函數(shù)的 prototype 屬性(圖) 每個(gè)函數(shù)都有一個(gè)prototype屬性,它默認(rèn)指向一個(gè)Object空對(duì)象(即稱為:原型對(duì)象) 原型對(duì)象中有...

    馬龍駒 評(píng)論0 收藏0

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

0條評(píng)論

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