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

資訊專欄INFORMATION COLUMN

深入理解Javascript原型關系

ethernet / 2679人閱讀

摘要:如下所示在規范中,已經正式把屬性添加到規范中也可以通過設置和獲取對象的原型對象對象之間的關系可以用下圖來表示但規范主要介紹了如何利用構造函數去構建原型關系。

前言

在軟件工程中,代碼重用的模式極為重要,因為他們可以顯著地減少軟件開發的成本。在那些主流的基于類的語言(比如Java,C++)中都是通過繼承(extend)來實現代碼復用,同時類繼承引入了一套類型規范。而JavaScript是一門弱類型的語言,從來不需要類型裝換,在JavaScript中變量可以指向任何類型的value(ES6規范中的類也只是語法糖,基于類的繼承本質上也是通過原型實現)。而基于原型的繼承模式可以說提供了更加豐富的代碼重用模式(后面再詳細講解JavaScript中的常用繼承模式,本文只專注于JavaScript中的原型),一個對象可以直接繼承另外一個對象,從而獲得新的方法和屬性。

適合人群

對JavaScript原型有一定了解,希望深入了解原型。

具有JavaScript相關開發經驗

不適合剛接觸JavaScript人員

對象

要理解JavaScript中的原型關系,首先必須弄清楚對象的基本概念。ECMAScript 5.1規范中描述的對象

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

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

原型
JavaScript的原型存在著諸多矛盾。它的某些復雜的語法看起來就像那些基于類的語言,這些語法的問題掩蓋了它的原型機制。它不直接讓對象從其他對象繼承,反而插入一個多余的間接層:通過構建器函數產生對象。——JavaScript語言精粹第5章節(繼承)

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

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

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

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
)

對象之間的關系可以用下圖來表示

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

下面利用構造函數來實現上述同樣功能

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
)

其中原型關系可以下圖表示

prototype__proto__屬性

我們看下規范中有關原型介紹的核心,更多詳情請閱讀ECMAScript 5.1 4.2.1章節

...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...

通過上面的描述我們可以得出以下結論

構造函數就是一個函數,函數中包含prototype屬性用來實現基于原型的繼承和共享屬性。通過Function.prototype.bind方法構造出來的函數是個例外,它沒有prototype屬性。

通過被構造函數創建的對象都有一個隱式的引用指向構造函數的prototype屬性。

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

構造函數說到底本質上也是一個普通函數,只是該函數專門通過new關鍵字來生成對象。所以JavaScript語言無法確定哪個函數是打算用來做構造函數的。所以每個函數都會得到一個prototype屬性,該屬性值是一個包含constructor屬性且constructor屬性值為該函數的對象,如下所示。

只有函數才擁有prototype屬性用來實現原型的繼承,其他對象并沒有。對象擁有__proto__指向其原型對象,JavaScript引擎可通過內部屬性[[prptotype]]獲取對象的原型對象。

關于這兩個屬性聯系可以用一句話概括:__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.

為什么要設計構造函數

如果你已經了解JavaScript原型,那我們可以來講講JavaScript語法為什么要設計構造函數。

首先來加深一遍概念:JavaScript是一門基于原型繼承的語言,這意味著對象可以直接從其他對象繼承屬性,該語言是無類型的。
然而這種設計是偏離主流方向的,當時主流語言JavaScript,C++都是通過 new Class 的語法來創建對象。JavaScript顯然對它的原型本質缺乏信心,所以它提供了一套和class語法類似的對象構建語法——也就是構造函數。通過instanceof操作符來判斷對象是否屬于某一類型。

instanceof 操作符

MDN介紹了其內部原理

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

instanceof操作符的語法

object instanceof constructor

簡單來說:instanceof 操作符就是判斷構造函數的prototype屬性值是否能在object對象的原型鏈中被找到,對就是這么簡單。這樣通過構造函數語法JavaScript引入了類的概念(偽類)。

最后的彩蛋

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

筆者就可能讀者遇到的問題備注如下:

Object.__proto__=== Function.prototype。Object本質上是一個built-in的全局構造函數,也是Function構造函數的實例。所以Object.__proto__ === Function.prototype.

Number,Date,Array等built-in構造函數都和Object構造函數一樣。

Function.prototype本質也是對象,所以其__proto__指向Object.prototype

最后

如果你最后還是沒有弄清楚JavaScript中的原型關系,可以在評論中進行描述我將盡我所能幫你答疑解惑。
或許你也可以看看參考文獻中的引用鏈接。

參考文獻

JavaScript. The Core: 2nd Edition

ecma-262

JavaScript Prototype in Plain Language

proto VS. prototype in JavaScript

Javascript語言精粹第五章節

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92859.html

相關文章

  • 深入學習js之——原型原型

    摘要:我們用一張圖表示構造函數和實例原型之間的關系好了構造函數和實例原型之間的關系我們已經梳理清楚了,那我們怎么表示實例與實例原型,也就是或者和之間的關系呢。 開篇: 在Brendan Eich大神為JavaScript設計面向對象系統的時候,借鑒了Self 和Smalltalk這兩門基于原型的語言,之所以選擇基于原型的面向對象系統,并不是因為時間匆忙,它設計起來相對簡單,而是因為從一開始B...

    FingerLiu 評論0 收藏0
  • 深入學習js之——原型原型

    摘要:我們用一張圖表示構造函數和實例原型之間的關系好了構造函數和實例原型之間的關系我們已經梳理清楚了,那我們怎么表示實例與實例原型,也就是或者和之間的關系呢。 開篇: 在Brendan Eich大神為JavaScript設計面向對象系統的時候,借鑒了Self 和Smalltalk這兩門基于原型的語言,之所以選擇基于原型的面向對象系統,并不是因為時間匆忙,它設計起來相對簡單,而是因為從一開始B...

    xialong 評論0 收藏0
  • 深入理解JavaScript

    摘要:深入之繼承的多種方式和優缺點深入系列第十五篇,講解各種繼承方式和優缺點。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執行了。 JavaScript深入之繼承的多種方式和優缺點 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優缺點。 寫在前面 本文講解JavaScript各種繼承方式和優缺點。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評論0 收藏0
  • JavaScript深入之從原型原型

    摘要:深入系列的第一篇,從原型與原型鏈開始講起,如果你想知道構造函數的實例的原型,原型的原型,原型的原型的原型是什么,就來看看這篇文章吧。讓我們用一張圖表示構造函數和實例原型之間的關系在這張圖中我們用表示實例原型。 JavaScript深入系列的第一篇,從原型與原型鏈開始講起,如果你想知道構造函數的實例的原型,原型的原型,原型的原型的原型是什么,就來看看這篇文章吧。 構造函數創建對象 我們先...

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

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

    馬龍駒 評論0 收藏0

發表評論

0條評論

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