JavaScript深刻之——原型與原型鏈

很長一段時間對JS的原型與原型鏈理解的很模糊,而想學好JS,原型與原型鏈倒是繞不開的話題,因此只好進行對其進行一個梳理。javascript

理解原型和原型鏈,需理解三個重要的屬性: prototype、__proto__、constructorjava

 

prototype函數

JavaScript函數中,每個函數都有一個prototype屬性,叫原型對象。spa

代碼示例:prototype

function Person(){

}

Person.prototype.name = 'zhangsan'
let person = new Person()

console.log(person.name)    // zhangsan

上面的代碼中,建立了一個構造函數Person,並在它的原型上添加一個屬性name爲zhangsan, 而後再建立了實例對象person,那麼這個實例對象上也有name屬性,打印輸出「zhangsan」3d

能夠看出:code

Person這個函數的prototype屬性指向了一個對象,即:Person.prototype 也是一個對象,這個對象正是調用該構造函數而建立的實例的原型,即person的原型。對象

方便理解,咱們進行拆解:blog

1.建立了構造函數Person

2.使用new關鍵字進行調用

3.調用獲得了實例person

4.實例和原型的關係:person的原型就是Person.prototype

  

那什麼是原型呢?能夠這樣理解:每個JavaScript對象(null除外)在建立的時候就會與之關聯另一個對象,這個對象就是咱們所說的原型,而每個對象都會從原型"繼承"屬性。繼承

咱們用一張圖表示構造函數和原型之間的關係:

構造函數和實例原型之間的關係咱們已經梳理清楚了,那怎麼表示實例與原型,也就是person和Person.prototype之間的關係呢?

 

__proto__

其實每個JavaScript對象(除了null)都有一個屬性,叫__proto__,這個屬性會指向該對象的原型。

代碼示例:

function Person(){

}

let person = new Person()
console.log(person.__proto__ === Person.prototype)   // true

構造函數Person的實例對象person,有個屬性叫__proto__,這個屬性指向原型,即Person.prototype。

補全上面的關係圖:

Q:原型是否有屬性指向構造函數或者實例對象呢?

 

constructor

代碼示例:

function Person() {

}
let person = new Person()
console.log(Person === Person.prototype.constructor); // true

 

繼續完善關係圖:

原型的constructor指向構造函數,但沒有屬性指向實例,由於可能有多個實例。

其實 person 中並無constructor 屬性,當不能讀取到constructor屬性時,會從 person 的原型也就是 Person.prototype中讀取

console.log(person.constructor === Person)   // true
console.log(person.constructor === Person.prototype.constructor)  // true

  

  

 實例與原型

當讀取實例的屬性時,若是找不到,就會查找與對象關聯的原型中的屬性,若是還查不到,就去找原型的原型,一直找到最頂層爲止。

代碼示例:

 function Person() {

}

Person.prototype.name = 'zhangsan';

let person = new Person();

 person.name = 'lisi';
 console.log(person.name) // lisi

delete person.name;
console.log(person.name) // zhangsan

 

new建立了一個實例對象person,有個屬性name值爲「lisi」,當咱們把刪除了這個name屬性後,依然可以打印出「zhangsan」,實際狀況是從 person 實例對象中找不到 name 屬性,就會從 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查找,幸運的是咱們找到了 name 屬性,結果爲 zhangsan

 

原型的原型

代碼示例:

Object.prototype.name = 'wangwu'

function Person(){

}

let person = new Person()
		
		
console.log(person.name)   // wangwu

Person 的實例對象person,自己沒有name屬性值,全部會去原型上找,Person.prototype上也沒有,就去原型的原型上找,即:Object.prototype,有一個name爲「wangwu」的屬性,全部輸出「wangwu」

其實原型對象就是經過Object構造函數生成的,結合以前咱們所說的,實例的__proto__指向構造函數的 prototype 因此咱們再豐富一下咱們的關係圖:

 

原型鏈

那Object.prototype 的原型呢?Object是根節點的對象,再往上查找就是null,咱們能夠打印:

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

 咱們將null也加入關係圖,就比較完整了:

 

上面的person實例對象到null的這條線即爲原型鏈。

 

咱們還能夠把大Function加上

console.log(Person.constructor === Function)  // true
console.log(obj.__proto__ === Object.prototype) // true
console.log(obj.__proto__.constructor === Object) /// true
console.log(obj.__proto__.constructor.__proto__ === Function.prototype) // true
console.log(obj.__proto__.constructor.__proto__.constructor === Function) // true
console.log(Person.__proto__ === Function.prototype) // true console.log(Object.__proto__ === Function.prototype) // true

 從網上找了張圖,如今再去理解原型與原型鏈,就好理解了吧

相關文章
相關標籤/搜索