這篇文章主要是學習一下JavaScript中的難點------原型和原型鏈
咱們學習一門編程語言,必然要使用它完成一些特定的功能,而面向對象的語言由於符合人類的認知規律,在這方面作得很好,今天我以JS爲例,探索一下JS不一樣於其餘面向對象的語言的地方-------原型和原型鏈
javascript
function Person(){ //構造函數 }
以上Person
就是一個構造函數,能夠用來生成小明
小紅
等等人類的實例。java
var person = new Person() //構造出一個對象 person.name = 'xiaoming' console.log(person.name) // 'xiaoming'
那原型在哪呢,認識原型先認識一下prototype
屬性git
先看一段代碼github
Person.prototype.name = 'god' var person2 = new Person() console.log(person2.name) //person2的名字是啥呢???
從上面三行代碼,猜一猜person2的名字是啥,沒錯,就是god
面試
person2沒有本身規定名字,可是Person構造函數的prototype上綁定了name,因此由Person構造函數構造的實例對象都默認有一個god
的名字。編程
以上就是構造函數和原型之間的關係,構造函數內部的prototype屬性指向了實例對象原型的地址。數組
name
。
上面紅框是Person實例的原型,若是不直觀的話,下面直接看Array實例的原型瀏覽器
紅框的都是你們熟悉的數組的方法吧,他們都放在數組的共有屬性裏面。編程語言
上面的兩幅原型圖裏面,咱們居然發現有共同點,都有一個熟悉 constructor
屬性,待會研究一下這個屬性。函數
如今,咱們已經知道了構造函數和原型的關係了,那person
person2
這些實例對象和原型有啥關係呢
__proto__
屬性每個構造的實例對象,內部有一個__proto__
屬性,它指向了實例原型,存的是原型的地址。
person.__proto__ === Person.prototype true
__proto__
是對象的屬性,並且是瀏覽器強逼着ECMAScript
加上的這個規範。
以上是構造函數、實例、實例原型之間的關係,不過方向是單向的,哪能不能讓它循環起來呢,原型可不能夠指向構造函數或者實例呢?
constructor嘛
構造函數、實例、實例原型之間的關係的方向能夠循環的關鍵就在這裏了。咱們一直叫構造函數,構造函數的,爲何這麼叫呢,對,就是這個原型裏面的constructor
屬性。
constructor
屬性指向 構造函數Person === Person.prototype.constructor true
上面就是經典的鐵三角了。
對象.__proto__ === 構造函數.prototype
而Person這個構造函數也是對象,那麼
Person.__proto__ === ???
上面的問號填啥呢,咱們按公式填空,應該是構造函數.prototype
,Person構造函數的構造函數是誰呢?沒錯,就是Function
。
Person.__proto__ === Function.prototype true
在控制檯驗證確實如此。
因此有些之前的疑惑也解開了
Array.__proto__ === Function.prototype true String.__proto__ === Function.prototype true
構造函數.prototype
也是對象啊,它指向誰__proto__
屬性Person.prototype.__proto__ === ???
問號填什麼呢,原型是由誰構造的呢,咱們想到了全部對象的根----------Object
在控制檯驗證以下
Person.prototype.__proto__ === Object.prototype true Array.prototype.__proto__ === Object.prototype true String.prototype.__proto__ === Object.prototype true
既然引出了Object,咱們來看一下全部對象的祖宗的原型吧
Object.prototype.__proto__ === null true
前面咱們看到了Function構造方法構造除了全部的函數,包括普通的構造函數。
那麼他自身也是一個函數,因此也是由Function構造函數構造的。因此由總結的公式能夠知道
Function.__proto__ === Function.prototype
並且,下面這個很重要,易錯
Function.prototype === Object.__proto__ //哈哈,這個老彆扭了吧,還給你倒過來寫,很容易錯的
解釋:Object也是構造函數啊,屬於對象。Object構造函數也是由Function把它構造出來的,因此是結果是true
- 當你new一個構造函數的時候,建立一個函數實例,那麼 『
函數實例.__proto__ === 該構造函數.prototype
』- 全部的函數都是由
Function
構造出來的,那麼 『被構造出來的其餘函數.__proto__ === Function.prototype
』- 全部的構造函數的原型對象都是由Object構造出來的,那麼 『
全部的構造函數.prototype.__proto__ === Object.prototype
』
instanceof
運算符的實質首先這有幾個題
Object instanceof Function Function instanceof Object Function instanceof Function Object instanceof Object
true
雖然 instanceof
運算符算是咱們的老朋友了,不過背後是咋判斷的呢
規範是這麼寫的
object instanceof constructor參數
object
要檢測的對象.
constructor
某個構造函數
instanceof
運算符用來檢測constructor.prototype
是否存在於參數object
的原型鏈上
Object instanceof Function
,Object.__proto__ === Function.prototype
爲true
,解決Function instanceof Object
, Function.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype
爲true
,解決。Function instanceof Function
,Function.__proto__ === Function.prototype
爲true
,解決Object instanceof Object
, Object.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype
爲true
,解決只要上面的推導,任一環節你寫錯或者壓根寫不出來(在今天以前我也是瞎搞,運氣好了蒙對了),說明你就不是真懂原型鏈,面試問到稍微變形的題仍是易錯。
Function
Object
構造函數也是對象
原型對象等全部對象都由Object構造
這四個點。
Object
Function
你把它們當作構造函數或者對象,結果不一樣的。不一樣的場合,換不一樣的角度去認識它們,事物具備兩面性。大概就是背了多年的同一性,巴拉巴拉一堆的哲學原理吧。__prto__屬性
有一條鏈子,找呀找呀,一直找到Object.prototype
爲止感謝 冴羽大神和若愚大神的 文章。