JavaScript進階 - 1. 原型和原型鏈的概念

JavaScript進階 - 1. 原型和原型鏈的概念

咱們好多常常會被問道JavaScript原型和原型鏈的概念,還有關於繼承,new操做符相關的概念。本文就專門整理了原型和原型鏈的概念,關於對象繼承咱們後邊進行介紹。本文包含對應的示例代碼和腦圖。若有奇異,歡迎指正!git

目錄講解

1. 構造函數建立對象

咱們先使用構造函數的方式聲明一個對象:函數

function Person() {}
let person = new Person()
person.name = '小紅'
console.log(person.name) // 小紅

在上面的代碼中。Person是構造函數, person是經過new方式建立的實例對象。
如今開始進入一個環節post

2. 相關的名詞介紹

prototype,constructor,__proto__是咱們常常見到的幾個概念,可是他們之間的關係具體是什麼樣的呢,讓咱們逐步開始瞭解。spa

2.1 prototype

每一個函數都有 prototype 屬性,除了 Function.prototype.bind(),該屬性指向原型, prototype: 指向實例對象的原型對象prototype

function Person() {}
Person.prototype.name = '小紅'
let person = new Person()
console.log(person.name) // 小紅

Person這個函數有聲明prototype屬性,那麼這個值指向的究竟是哪兒,是原型對象嗎?code

其實prototype指向的是,調用當前構造函數建立實例對象的原型,也就是person的原型。對象

那麼原型究竟是什麼呢?其實原型能夠理解爲,一個JavaScript對象(null除外)在建立的時候會關聯另一個對象,這個被關聯的對象就是咱們說的原型對象,實例對象會在建立的時候,從原型對象繼承一些屬性或者方法。繼承

對應的關係圖以下:
imageip

2.2 proto

prototype講解了構造函數和原型對象之間的關係,那麼實例對象和原型對象之間的關係又是怎麼樣的呢?下面講解。每一個JavaScript對象(null除外),都會有個__proto__的屬性,這個屬性指向的就是原型對象

function Person() {}
let person = new Person()
console.log(person.__proto__ === Person.prototype) // true
// ES5  經過實例對象獲取原型對象的方法
console.log(Object.getPrototypeOf(person) === Person.prototype) // true

由此咱們上面的管理系圖譜能夠補充爲:
1562491022186-2.png

2.3 constructor

上面講解了原型對象和構造函數,實例對象之間的關係,那麼反過來獲取原型對象和實例對象的構造函數是否是能獲取到呢??constructor就能作到這一點。constructor: 指向該原型對象對應的構造函數

function Person() {}
let person = new Person()
// 原型對象的構造函數
console.log(Person.prototype.constructor === Person) // true
// 實例對象的構造函數
console.log(person.constructor === Person)  // true
// 實例對象自己是否含有constructor屬性
console.log(person.hasOwnProperty('constructor'))  // false

注意:
person.constructor 中其實是沒有constructor屬性的,這是從person的原型中獲取到的constructor屬性纔有了  person.constructor === Person。經過

關係圖能夠補充爲:
1562491057091-3.png

3. 實例和原型 原型和原型

3.1 實例和原型

當咱們讀取一個對象的屬性是,若是實例對象中能找到,就會返回實例對象對應的value,若是沒有找到,就會站到實例對象的原型對象中,查看有無此值,有則返回,沒有的話,繼續查找原型的原型對象上有無此值。一直會查到頂層爲止。

function Person() {}
Person.prototype.name = '小紅'

let person1 = new Person()
let person2 = new Person()

person2.name = '小明'
console.log(person1.name) //小紅
console.log(person2.name) //小明

那麼原型的原型執行的是什麼呢?

3.2 原型和原型

實際上,原型的原型也是一個實例對象,是經過Object的構造函數生成的,所以,原型的原型也能經過__proto__獲取其對應的原型對象的屬性。

function Person() {}
Object.prototype.name = 'sunny'

let person1 = new Person()
let person2 = new Person()

console.log(person1.name) //sunny
console.log(person2.name) //sunny

對應的關係圖以下:
1562492884827-4.png

4. 原型鏈是怎麼產生的(附有相關的關係圖說明)

console.log(Object.prototype.__proto__ === null) // true

Object.prototype的原型爲null, null表明的意思是沒有對象,爲空。換句話的意思就是說,沒有原型對象了,這也就是查找的頂層對象了。

整個的關係圖咱們梳理爲:
1562493193715-5.png

關係圖中,紅色的線其實就是咱們平時說的原型鏈

擴展內容

  1. 咱們知道函數其實也是一個對象,任何函數都能當作是Function()經過new實例化後的結果。所以,若是把Person和Object當作是實例對象的話,他們的原型指向的是構造函數Function()的實例對象Function.prototype。
console.log(Person.__proto__ === Function.prototype) //true
console.log(Object.__proto__ === Function.prototype) //true
  1. 原型對象Function.prototype的constructor指向的是構造函數Function,Person和Object自己沒有constructor屬性,可是其原型對象有該屬性,所以也能獲取到構造函數。
console.log(Function.prototype.constructor === Function) // true
console.log(Person.constructor === Function) //true
console.log(Person.hasOwnProperty('constructor')) //false
console.log(Object.constructor === Function) //true
console.log(Object.hasOwnProperty('constructor')) //false
  1. 全部的函數對象均可以當作是Function經過new以後生成的實例對象,那麼Function能夠當作是本身調用本身實例化的結果產生的。所以有Function的實例對象指向Function.prototype
console.log(Function.prototype === Function.__proto__) // true
console.log(Function.prototype === Function.prototype) //true
  1. 若是此時的Function.prototype做爲實例,那麼他本身的實例對象執行的又是誰呢?全部的對象均可以看做是Object實例化的結果。因此,Function.prototype的原型對象是Object.prototype,其原型函數是Object()。
console.log(Function.prototype.__proto__ === Object.prototype);  //true

把這些所有總結完,以後咱們的關係圖,就變成了下面這個樣子:
1562495972314-6.png

參考文章

JavaScript深刻之從原型到原型鏈

一張圖理解JS的原型(prototype、_proto_、constructor的三角關係)

相關文章
相關標籤/搜索