完全瞭解instanceof的底層實現原理

1、做用
①用於判斷某個實例是否屬於某構造函數
②在繼承關係中用來判斷一個實例是否屬於它的父類型或者祖先類型的實例
說白了,只要右邊變量的 prototype 在左邊變量的原型鏈上便可。所以,instanceof 在查找的過程當中會遍歷左邊變量的原型鏈,直到找到右邊變量的 prototype,若是查找失敗,則會返回 false函數

2、語法
[對象] instanceof [構造函數]
如:this

var obj = new Object()
obj instanceof Object // true

3、涉及的構造函數
基礎類型:String、Number、Boolean、Undefined、Null、Symbol
複雜類型:Array,Object
其餘類型:Function、RegExp、Dateprototype

4、底層原理code

function instance_of(L, R) {
    var O = R.prototype; 
    L = L.__proto__;
    while (true) {    
        if (L === null)      
             return false;   
        if (O === L) 
             return true;   
        L = L.__proto__;  
    }
}

代碼解釋:
①L表示對象實例,R表示構造函數或者父類型實例
②取R的顯式原型,取L的隱式原型
③循環遍歷,進行判斷②中的兩個值是否相等,相等返回true,不相等繼續查找L的原型鏈對象

5、未發生繼承關係時繼承

function Cat(name,age,type){
    this.name = name;
    this.age = age;
    this.type = type;
}
function Dog(name){
    this.name = name;
}
var cats = new Cat('有魚',2,'英短');
var dogs = new Dog('哈士奇');
console.log(cats instanceof Cat);  // true
console.log(dogs instanceof Dog);  // true
console.log(cats instanceof Object);  // true
console.log(dogs instanceof Object);  // true

先看一下「cats instanceof Cat」運行狀況:原型鏈

function instance_of(L, R) { // L即cats   R即Cat
    var O = R.prototype; //O爲Cat.prototype
    L = L.__proto__;       // L爲cats._proto_
    while (true) {    //執行循環
        if (L === null)   //不經過
            return false;   
        if (O === L)       //判斷:Cat.prototype ===cats._proto_
                return true;  //若是等於就返回true,證實cats是Cat類型
        L = L.__proto__;   
    }
}

再看一下「cats instanceof Object」運行狀況:原型

function instance_of(L, R) { //L即cats  R即Object     
    var O = R.prototype;  //O爲Object.prototype    
    L = L.__proto__;    // L爲cats._proto_        
    while (true) {     //執行循環      
        if (L === null)   //不經過  
            return false;      
        if (O === L)   // 此時判斷Object.prototype === cats._proto_ 顯然不成立
             return true;                         
         L = L.__proto__;   //遍歷cats的原型鏈,即此時L爲 cats._proto_ ._proto_,
                          //即Cat.prototype._proto_指向的對象,
                         //接着執行循環,
                         //到Object .prototype === cats._proto_ ._proto_
                         //成立,返回true
    }
}

6、產生繼承關係時io

function Cat(name,age,type){
    this.name = name;
    this.age = age;
    this.type = type;
}
function YingDuan(name,age,type,sex){
    Cat.call(this,name,age,type);  
    this.sex = sex;
}
YingDuan.prototype = new Cat();  // 這裏改變了原型指向,實現繼承
var yd = new YingDuan("有魚",2,"金漸層","男"); //建立了英短對象yd
console.log(yd instanceof YingDuan);    // true
console.log(yd instanceof Cat);    // true
console.log(yd instanceof Object);    // true

先看一下「yd instanceof YingDuan」運行狀況:console

function instance_of(L, R) { //L即yd  R即YingDuan
   var O = R.prototype;  //O爲YingDuan.prototype,如今指向了cat
    L = L.__proto__;    //L爲yd._proto_,也隨着prototype的改變而指向了cat
    while (true) {    //執行循環
        if (L === null)  //不經過
            return false;   
        if (O === L)    //判斷是否 YingDuan.prototype ===yd._proto_ 
            return true;  //此時,兩方都指Cat的實例對象cat,因此true
        L = L.__proto__;       
    }
}

再看一下「yd instanceof Cat」運行狀況,即如何判斷yd繼承了Cat:

function instance_of(L, R) { // L即yd  R即Cat  
   var O = R.prototype; // O爲Cat.prototype    
    L = L.__proto__;   //L爲yd._proto_,如今指向的是cat實例對象
    while (true) {   // 執行循環   
       if (L === null)   //不經過    
           return false;         
       if (O === L)    //判斷是否 Cat.prototype === yd._proto_   
            return true;   //此時,yd._proto_ 指向cat實例對象,並不知足
        L = L.__proto__;  //令L=  yd._proto_._proto_,執行循環
   }                      //yd._proto_ ._proto_,指的就是Cat.prototype,因此也返回true
}                         //這就證實了yd繼承了Cat

yd instanceof Object也是同理的,這裏暫不贅述。

7、注意問題
instanceof 用於判斷對象類型,但如下狀況的結果都爲false,請注意

console.log(Number instanceof Number)  // false
console.log(String instanceof String)  // false
console.log(Fun instanceof Fun)        // false,這裏Fun指的是函數
console.log(null instanceof Object)   // false,null不具備任何對象的特性,也沒有__proto__屬性
相關文章
相關標籤/搜索