探討instanceof實現原理,並用兩種方法模擬實現 instanceof
在開始之前先了解下js數據類型
js基本數據類型:
null undefined number boolean string
js引用數據類型:
function object array
一說instanceof 就想到typeof ,這裏也介紹下typeof:
typeof是用來判斷數據類型的,就一個參數 ,使用方式像這樣: typeof num, 就是判斷num是什麽類型
typeof 一般只能返回如下幾個結果:"number"、"string"、"boolean"、"object"、"function" 和 "undefined"; 除了"object" 其他都好說。
著重看這幾個:
typeof 不存在的變量 = “undefined”
typeof 對象 = “object”
typeof null = "object"
typeof 數組 = “object”
typeod 方法的實例(比如 new Array()) =“object”
對象,數組 都是引用類型, 使用typeof 結果是 object類型,但是null 是基本數據類型,使用typeof結果也是 object,
可以這麽理解:null 是 不指向任何對象 的 空指針, 因為它是指向對象的,所以typeof 就是 object, 但是它又是空的,所以就屬於基本數據類型。
但是要想判斷一個變量是不是數組, 或者對象, 這時候就需要instanceof了(判斷是不是null,直接用 變量 === null 就行, null===null 結果是 true)
現在說instanceof, 要想從根本上了解 instanceof 的奧秘,需要從兩個方面著手:
1 語言規範中是如何定義這個運算符的。
2 JavaScript 原型繼承機制。
一 JavaScript instanceof 語言規範 (簡化版) 的運算代碼如下:
function instance_of(L, R) {//L 表示左表達式,R 表示右表達式 var O = R.prototype; L = L.__proto__; while (true) { if (L === null) return false; if (O === L) // 這裏重點:當 O 嚴格等於 L 時,返回 true return true; L = L.__proto__; } }
規則簡單來說就是 L的 __proto__ 是不是強等於 R.prototype,不等於再找 L.__proto__ .__proto__ 直到 __proto__ 為 null
二 JavaScript 原型鏈,看下圖:
對上圖的說明:
1.function Foo 就是一個方法,比如內置的 Array ,String ,或者自定義的方法;
2.function Object 就是Object
3.function Function 就是Function
4.以上三個其實都是function 所以他們的_proto_ 都是Function.prototype
5.記住 String, Array, Number, Object, Function這些其實都是 function
結合語言規範跟js的原型鏈,接下來我們看實際例子
常規的用法:
function F(){}
var a = new F()
console.log(a instanceof F) // 輸出 true
function child(){}
function father(){}
child.prototype = new father()
var a = new child()
console.log(a instanceof father) // 輸出true
更高級點的用法:
console.log(Object instanceof Object);//true
console.log(Function instanceof Function);//true
console.log(Number instanceof Number);//false
console.log(String instanceof String);//false
console.log(Function instanceof Object);//true
console.log(Foo instanceof Function);//true
console.log(Foo instanceof Foo);//false
大家可以在控制臺輸出,可以直觀的看到每個步驟的輸出,結合instanceof 的規範跟js原型鏈 加深理解。
模擬實現instanceof
對於用 typeof 就可以判斷出來數據類型的這裏就不處理,只處理 typeof 結果為 object ,並且不是 null 的。
方法一: 直接使用instanceof的規則
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
function instance_of(L, R) {//L 表示左表達式,R 表示右表達式
var O = R.prototype;
L = L.__proto__;
while (true) {
if (L === null)
return false;
if (O === L) // 這裏重點:當 O 嚴格等於 L 時,返回 true
return true;
L = L.__proto__;
}
}
// 開始測試
var a = []
var b = {}
function Foo(){}
var c = new Foo()
function child(){}
function father(){}
child.prototype = new father()
var d = new child()
console.log(instance_of(a, Array)) // true
console.log(instance_of(b, Object)) // true
console.log(instance_of(b, Array)) // false
console.log(instance_of(a, Object)) // true
console.log(instance_of(c, Foo)) // true
console.log(instance_of(d, child)) // true
console.log(instance_of(d, father)) // true
</script>
</body>
</html>
方法二:在方法一的基礎上使用 constructor (此方法無法用於判斷繼承)
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
function instance_of(L, R) {//L 表示左表達式,R 表示右表達式
var O = R;
L = L.__proto__;
while (true) {
if (L === null)
return false;
if (O === L.constructor) // 這裏重點:當 O 嚴格等於 L 時,返回 true
return true;
L = L.__proto__;
}
}
// 開始測試
var a = []
var b = {}
function Foo(){}
var c = new Foo()
function child(){}
function father(){}
child.prototype = new father()
var d = new child()
console.log(instance_of(a, Array)) // true
console.log(instance_of(b, Object)) // true
console.log(instance_of(b, Array)) // false
console.log(instance_of(a, Object)) // true
console.log(instance_of(c, Foo)) // true
console.log(instance_of(d, child)) // false 這裏就是無法用於判斷繼承的
console.log(instance_of(d, father)) // true
</script>
</body>
</html>
探討instanceof實現原理,並用兩種方法模擬實現 instanceof