JS開發者應懂的33個概念系列5(下)--typeof 與 instanceof && 23--原型繼承與原型鏈
typeof的原理
typeof
可以用來判斷原始值的型別,以及區分物件值和原始值.我們可以利用 typeof
來判斷number
, string
, object
, boolean
, function
, undefined
, symbol
這七種型別。
一個 js
的變數,在它的底層實現中, 型別資訊是怎麼實現的呢?也就是說js 在底層是怎麼儲存資料的型別資訊呢?typeof
也就是通過型別資訊進行判斷的。
js 在底層儲存變數的時候,會在變數的機器碼的低位1-3位儲存其型別資訊:
- 000
object
- 010
浮點數
- 100
string
- 110
boolean
- 1
整數
對於 undefined
和 null
來說,這兩個值的資訊儲存是有點特殊的。
null
:所有機器碼均為0undefined
:用 −2^30 整數來表示
所以,typeof
在判斷 null
的時候就出現問題了,由於 null
的所有機器碼均為0,因此直接被當做了物件來看待。所以,在判斷變數型別的時候,避免對null
進行判斷。
typeof null // "object"
複製程式碼
instanceof的原理
在 JavaScript 中,判斷一個變數的型別嚐嚐會用 typeof
運算子,在使用 typeof
運算子時採用引用型別儲存值會出現一個問題,無論引用的是什麼型別的物件,它都返回 "object"
直接上硬貨:
function instance_of(L, R) {//L 表示左表示式,R 表示右表示式
var O = R.prototype;// 取 R 的顯示原型
L = L.__proto__;// 取 L 的隱式原型
while (true) {
if (L === null)
return false;
if (O === L)// 這裡重點:當 O 嚴格等於 L 時,返回 true
return true;
L = L.__proto__;
}
}
複製程式碼
instanceof
在查詢的過程中會遍歷左邊變數的原型鏈,直到找到右邊變數的 prototype
,如果查詢失敗,則會返回 false
,告訴我們左邊變數並非是右邊變數的例項。
劃重點,原型鏈
原型鏈
function Person() {}
var Student = new Person()
複製程式碼
先不著急解釋原型鏈,先看一下什麼是原型?
原型
- 每一個建構函式都擁有一個
prototype
屬性,這個屬性指向一個物件,也就是原型物件。比如:建構函式Person
的prototype
便是指向Person.prototype
物件。 - 原型物件預設擁有一個
constructor
屬性,指向它的那個建構函式(也就是說建構函式和原型物件是互相指向的關係)。比如:Person.prototype.constructor
指向Person
。 - 每個物件型別比如(
Student
,Person.prototype
,Function.prototype
)都擁有一個隱藏的屬性[[prototype]]
,指向它的原型物件,這個屬性可以通過Object.getPrototypeOf(obj)
或obj.__proto__
來訪問。 - 實際上,建構函式的prototype屬性與它建立的例項物件的
[[prototype]]
屬性指向的是同一個物件,即Student.__proto__ === Person.prototype
。
在JavaScript
中,所有的物件都是由它的原型物件繼承而來,反之,所有的物件都可以作為原型物件存在。
訪問物件的屬性時,JavaScript
會首先在物件自身的屬性內查詢,若沒有找到,則會跳轉到該物件的原型物件中查詢,也就是通過__proto__
進行查詢。
所以呢,原型鏈就是你查詢過程所經歷的地方。
最後來個例子:
console.log(Object instanceof Object);//true
console.log(Function instanceof Function);//true
console.log(Function instanceof Object);//true
複製程式碼
在複習一遍:
Object instanceof Object?
var O = Object.prototype;
var L = Object.__proto__; // L是Function.prototype
while(true) // 進入迴圈
L = Object.__proto__.__proto__ // L是Object.prototype
while(true) // 重新進入迴圈
O === L
return true;
複製程式碼
總結口訣
Object.__proto__ === Function.prototype
其中Object
是建構函式- 指向
Function.prototype
是建構函式的__proto__
屬性 - 指向
Object.prototype
是原型物件的__proto__
屬性 Object.prototype.__proto__
是null
*.prototype.constructor
指向它的建構函式*
Object.prototype
除了constructor
和__proto__
外,還有toString()
,valueOf()
等屬性,下屬原型物件可以通過原型鏈繼承這些屬性。