JavaScript基礎專題之原型與原型鏈(一)

構造函數建立對象

function Person(){

}
let person1 = new Person()
let person2 = new Person()
person1.name = 'james'
person2.name = 'kobe'

複製代碼

咱們經過new來建立一個person實例,咱們能夠看到不一樣的實例擁有本身的屬性。

proto

咱們能夠看到每一個對象下都會有__proto__的屬性,這個屬性會指向該對象的原型數組

function Person(){

}
Person.prototype.name = 'chris'
let person = new Person()
let person1 = new Person()
let person2 = new Person()

person1.name = 'james'
person2.name = 'kobe'
複製代碼

咱們看到 __proto__下會出現prototype的name屬性,那麼 __proto__prototype關係又是什麼呢?

prototype

每一個函數都有具備 prototype屬性,就是咱們常常在用到的prototypebash

Person.prototype.name = 'chris'
複製代碼

那麼問題來了,那這個函數的 prototype 屬性到底指向的是什麼呢?是這個函數的原型嗎? 其實,函數的 prototype 屬性指向了一個對象,這個對象正是調用該構造函數而建立的實例的原型,也就是這個例子中的 person1 和 person2 的原型。函數

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

如圖:ui

經過實例的__proto__和構造函數的prototype的對比,咱們不難發現person 和 Person.prototype 的關係spa

person.__proto__ === Person.prototype  //true
複製代碼

如圖:prototype

既然實例對象和構造函數均可以指向原型,那麼原型是否有屬性指向構造函數或者實例呢?翻譯

constructor

不難發現,每一個構造函數都有 constructor這個屬性, 經過控制檯咱們會發現constructor 屬性指向關聯的構造函數code

constructor

指向本身實例.png

這樣咱們就瞭解了構造函數、實例原型、和實例之間的關係,接下來咱們講講實例和原型的關係:cdn

實例下的原型

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

function Person() {

}

Person.prototype.name = 'chris';

var person = new Person();

person.name = 'james';
console.log(person.name) // james 拿到實例的name屬性

delete person.name;
console.log(person.name) // chris 拿到原型的name屬性
複製代碼

可是萬一尚未讀取到呢?原型下的原型又是什麼呢?

原型下的原型

經過上面的知識咱們知道person.__proto__Person.protype相等,那麼Person.prototype.__proto__下又是什麼呢?很顯然就是對象實例的__proto__

function Person(){}
let person = new Person()
let obj = new Object()
Person.prototype.__proto__ === obj.__proto__//true
Person.prototype.__proto__ === Object.prototype//true
obj.__proto__.__proto__ //null
複製代碼

let obj = new Object();
obj.__proto__.name = 'chris'
obj.name = 'Kevin'
console.log(obj.name) // Kevin
delete obj.name
console.log(obj.name) // chris
複製代碼

原型鏈

既然咱們知道Object的原型,那 Object.prototype的原型呢?

咱們能夠看到返回一個 null,表達的就是已經沒有原型了。

最終就是原型和原型鏈的結構

一些補充

  1. 關於Funtion中的原型 咱們能夠會發現Function.prototype有些特殊
Function.prototype === Function.__proto__  //true
複製代碼

這樣看上去實例的原型和原型的原型是相等的,便是雞也是蛋。 咱們能夠參考MDN關於__proto__的解釋:

__proto__的讀取器(getter)暴露了一個對象的內部 [[Prototype]] 。對於使用對象字面量建立的對象,這個值是 Object.prototype。對於使用數組字面量建立的對象,這個值是 Array.prototype。對於functions,這個值是Function.prototype。對於使用 new fun 建立的對象,其中fun是由js提供的內建構造器函數之一(ArrayBooleanDateNumberObjectString 等等),這個值老是fun.prototype。對於用js定義的其餘js構造器函數建立的對象,這個值就是該構造器函數的prototype屬性。

例子

Object.__proto__ === Function.prototype//true
Object.__proto__ === Function.__proto__ //true
複製代碼

引用冴羽的理解

至於爲何Function.__proto__ === Function.prototype,我認爲有兩種可能:一是爲了保持與其餘函數一致,二是就是代表一種關係而已。 簡單的說,就是先有的Function,而後實現上把原型指向了Function.prototype,可是咱們不能倒過來推測由於Function.__proto__ === Function.prototype,因此Function調用了本身生成了本身。

總結

  1. 實例對象的__proto__始終指向構造函數的prototype

  2. 只有構造函數才擁有prototype屬性,對象(除了null)都擁有__proto__屬性

  3. 每個原型對象都有一個constructor屬性指向它們的構造函數

  4. 要讀取屬性時,先讀取實例上的屬性,讀取不到會在原型鏈上尋找相應屬性

  5. 原型鏈按照__proto__的指向下一級對象

  6. 原型鏈的盡頭始終是null

  7. 構造函數實例化之後,既是構造函數函數,也是對象

function Foo() {

}

const obj = new Foo()


Foo.prototype === obj.__proto__ //true
obj.constructor === Foo //true
Foo.prototype.__proto__ === Object.prototype //true
Object.prototype.__proto__ === null //true
Object.constructor === Function  //true
複製代碼

JavaScript基礎專題系列

JavaScript基礎專題系列目錄地址:

JavaScript基礎專題之原型與原型鏈(一)

JavaScript基礎專題之執行上下文和執行棧(二)

新手寫做,若是有錯誤或者不嚴謹的地方,請大夥給予指正。若是這篇文章對你有所幫助或者有所啓發,還請給一個贊,鼓勵一下做者,在此謝過。

相關文章
相關標籤/搜索