function Person(){
}
let person1 = new Person()
let person2 = new Person()
person1.name = 'james'
person2.name = 'kobe'
複製代碼
咱們能夠看到每一個對象
下都會有__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
bash
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
屬性指向關聯的構造函數code
這樣咱們就瞭解了構造函數、實例原型、和實例之間的關係,接下來咱們講講實例和原型的關係: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
,表達的就是已經沒有原型了。
最終就是原型和原型鏈的結構
Funtion
中的原型 咱們能夠會發現Function.prototype
有些特殊Function.prototype === Function.__proto__ //true
複製代碼
這樣看上去實例的原型和原型的原型是相等的,便是雞也是蛋。 咱們能夠參考MDN關於__proto__
的解釋:
__proto__的讀取器(getter)暴露了一個對象的內部
[[Prototype]]
。對於使用對象字面量建立的對象,這個值是Object.prototype
。對於使用數組字面量建立的對象,這個值是Array.prototype
。對於functions,這個值是Function.prototype
。對於使用 new fun 建立的對象,其中fun是由js提供的內建構造器函數之一(Array
,Boolean
,Date
,Number
,Object
,String
等等),這個值老是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
調用了本身生成了本身。
實例對象的__proto__
始終指向構造函數的prototype
只有構造函數才擁有prototype
屬性,對象(除了null)都擁有__proto__
屬性
每個原型對象都有一個constructor
屬性指向它們的構造函數
要讀取屬性時,先讀取實例上的屬性,讀取不到會在原型鏈上尋找相應屬性
原型鏈按照__proto__
的指向下一級對象
原型鏈的盡頭始終是null
構造函數實例化之後,既是構造函數函數,也是對象
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基礎專題系列目錄地址:
新手寫做,若是有錯誤或者不嚴謹的地方,請大夥給予指正。若是這篇文章對你有所幫助或者有所啓發,還請給一個贊,鼓勵一下做者,在此謝過。