JS之typeof和instanceof方法具體實現

1、typeof方法的做用

  • 判斷變量類型
typeof 1 //"number"
typeof '1' //"string"
typeof {} //"object"
typeof true //"boolean"
typeof undefined // "undefined"
typeof null //"object" #bug
typeof Symbol //"function"
typeof Symbol(1) //"symbol"
複製代碼

2、typeof方法的具體實現

if (JSVAL_IS_VOID(v)) {  // (1)
    type = JSTYPE_VOID;
} else if (JSVAL_IS_OBJECT(v)) {  // (2)
    obj = JSVAL_TO_OBJECT(v);
    if (obj &&
        (ops = obj->map->ops,
            ops == &js_ObjectOps
            ? (clasp = OBJ_GET_CLASS(cx, obj),
            clasp->call || clasp == &js_FunctionClass) // (3,4)
            : ops->call != 0)) {  // (3)
        type = JSTYPE_FUNCTION;
    } else {
        type = JSTYPE_OBJECT;
    }
} else if (JSVAL_IS_NUMBER(v)) {
    type = JSTYPE_NUMBER;
} else if (JSVAL_IS_STRING(v)) {
    type = JSTYPE_STRING;
} else if (JSVAL_IS_BOOLEAN(v)) {
    type = JSTYPE_BOOLEAN;
}
複製代碼

根據 type tags 的信息,低位是 000,所以 null 被判斷成了一個對象。這就是爲何 typeof null 的返回值是 objectMDN 有簡單的描述解釋了緣由,並且之後也不會修復這個 bug ,由於修復這個 bug 會帶來更多的問題。數組

3、更準確的類型判斷方法

因爲 typeof存在 null 的類型爲 object,因此能夠用另一種更加準確的方法來判斷基本類型,那就是Object.prototype.toStringbash

Object.prototype.toString.call(2) // "[object Number]"

Object.prototype.toString.call('hello') // "[object String]"

Object.prototype.toString.call({hello:'hello'}) // "[object Object]"

Object.prototype.toString.call([2,'hello']) // "[object Array]"

Object.prototype.toString.call(true) // "[object Boolean]"

Object.prototype.toString.call(() => {}) // "[object Function]"

Object.prototype.toString.call(null) // "[object Null]"

Object.prototype.toString.call(undefined) // "[object Undefined]"

Object.prototype.toString.call(Symbol(2)) // "[object Symbol]"

複製代碼

4、instanceof方法的做用

  • 判斷一個引用是否屬於某個構造函數
  • 判斷繼承關係中一個實例是否屬於其父類 好比:
const Animal = function(type) {
  this.type = type;
}
const cat= new Animal('cat');
console.log(cat instanceof Animal);  //true
console.log(cat instanceof Object); //true
複製代碼

5、如何實現一個instanceof方法

function myInstanceof(leftVaule, rightVaule) { 
    let rightProto = rightVaule.prototype; // 取右邊 prototype的值
    leftVaule = leftVaule.__proto__; // 取左邊__proto__值
    while (true) {
    	if (leftVaule === null) { //若是左邊的__proto__值爲null,返回false
            return false;	
        }
        if (leftVaule === rightProto) { //若是左邊的__proto__值等於右邊prototype的值,返回true
            return true;	
        } 
        leftVaule = leftVaule.__proto__ ; //以上都不知足,取上一層原型繼續循環,直到沒取到爲null
    }
}
複製代碼

其實說白了就是在實例的原型鏈上面去找,看到底有沒有找到右邊的原型,找到了就返回 true,沒找到或者左邊不存在原型鏈,就返回 false。 例子:函數

function Foo() {
}

myInstanceof(Object, Object) // true
myInstanceof(Function , Function)  // true
myInstanceof(Function , Object ) // true
myInstanceof(Foo, Foo) // false
myInstanceof(Foo, Object) // true
myInstanceof(Foo, Function) // true
複製代碼

6、總結

typeofinstanceof 能夠用來判斷一些基本類型及原型鏈的實例與原型之間的關係,可是使用的時候也須要很當心,由於一些潛在的問題會致使意外的問題出現,好比數組的判斷:post

[1,2] instanceof Array //true
[1,2] instanceof Object //true
複製代碼

這是由於ui

Array instanceof  Object //true
複製代碼

可能這並非咱們想要的結果,因此能夠使用更加準確的判斷方法 Object.prototype.toString.callthis

Object.prototype.toString.call( [1,2,3] ) //"[object Array]"
複製代碼

此外,instanceof 方法的具體實現需熟練掌握。spa

7、參考

juejin.im/post/5b0b9b…prototype

相關文章
相關標籤/搜索