`今天看了github上面的某位大佬對原型與原型鏈的文章 講解很透徹` 文章下麵貼地址 prototype 每個函數都有prototype屬性,如下 這個函數的prototype到底是什麼呢,是函數的原型嗎? 其實,函數的prototype都會指向一個對象,這個對象 就是調用改構造函數而創建的 ,也 ...
今天看了github上面的某位大佬對原型與原型鏈的文章 講解很透徹
文章下麵貼地址
prototype
每個函數都有prototype屬性,如下
這個函數的prototype到底是什麼呢,是函數的原型嗎?
其實,函數的prototype都會指向一個對象,這個對象 就是調用改構造函數而創建的實例的原型
,也就是上圖的a b的原型
什麼是原型呢?
每一個JavaScript對象(null除外)在創建的時候就會與之關聯另一個對象,這個對象就是我們所說的原型,每一個對象都會從原型"繼承"屬性。
用過一張圖來表示構造函數與實例之間的關係
那麼上面的變數 ab是怎麼訪問到score的prototype.name的呢?
這裡就要提出第二個屬性
___ proto ___
這是每個JavaScript對象都會有的屬性 叫做_ proto _ 這和屬性 指向該對象的原型 即是
JavaScript function score () {} score.prototype.name = "張三" var b= new score() b.__proto__.name //"張三"
這裡可以看到 b._ proto_ 是指向score.prototype的 或者我們可以證明
score.prototype == b.__proto__ //true
現在我們知道
構造函數 prototype 指向原型 構造函數可以生成實例 實例的 _ proto _ 指向原型
於是關係圖可以這麼理解
這裡構造函數 和 實例都指向 原型 那麼會不會有 原型指向構造函數與實例呢?
#### constructor
沒有指向實例的方法 因為 會有多個實例 但是有指向構造函數的方法 就是constructor 每個原型都有一個constructor屬性指向關聯的構造函數
可以看出來constructor指向構造函數本身
總結一下 現在得出結論
3
console.log(score.prototype.constructor == score)
console.log(score.prototype == a.__proto__)
再更新一下圖
實例與原型
當讀取實例的屬性時,如果找不到,就會查找與對象關聯的原型中的屬性,如果還查不到,就去找原型的原型,一直找到最頂層為止。
function score () {}
score.prototype.age="20" //在原型鏈上面賦值 age = 20
var a = new score()
a.age
"20" //age指向原型鏈上面
a.age= "10"
"10" //這時候指向a實例上面
delete a.age;
a.age
"20" //age指向原型鏈
當實例沒有age這個屬性 他會在原型鏈上面找
當給實例賦值的時候 就會覆蓋prototype上面的屬性 但是 prototype上面的屬性依舊存在
當將實例上面的age刪除的時候 就會依舊列印出原型鏈上面的屬性
這裡思考一個問題 JavaScript萬物皆對象 name prototype的對象是什麼呢?
原型的原型
我們已經講了原型也是一個對象,既然是對象,我們就可以用最原始的方式創建它
Object.prototype.name = "張三"
var obj = new Object();
console.log(obj.name) // 張三 //和上面同理 來自原型鏈上面的name
Object.prototype.constructor == Object
現在關係圖再次更新
原型鏈
那 Object.prototype 的原型呢?
console.log(Object.prototype.__proto__)
null
null 表示“沒有對象”,即該處不應該有值
所以 Object.prototype.proto 的值為 null 跟 Object.prototype 沒有原型,其實表達了一個意思。
最後整理關係圖
圖中由相互關聯的原型組成的鏈狀結構就是原型鏈,也就是藍色的這條線。
最讓人不註意的就是日常引用要註意的問題
首先 看下麵代碼
function score () {}
var a = new score()
console.log(a.constructor == score)
答案是 true
當獲取 a.constructor 時,其實 a中並沒有 constructor 屬性,當不能讀取到constructor 屬性時,會從 a的原型也就是 score.prototype 中讀取,正好原型中有該屬性,所以相當於:
person.constructor === Person.prototype.constructor
學過java的人可能會將JavaScript的原型鏈理解為繼承 但是 JavaScript裡面一直以來都沒有這個說法
你不知道的JavaScript
裡面有一句話
繼承意味著複製操作,然而 JavaScript 預設並不會複製對象的屬性,相反,JavaScript 只是在兩個對象之間創建一個關聯,這樣,一個對象就可以通過委托訪問另一個對象的屬性和函數,所以與其叫繼承,委托
的說法反而更準確些。