JS 数据类型判定 typeof原理 instanceof原理

typeof

typeof 一般被用于判断一个变量的类型,我们可以利用 typeof 来判断number, string, object, boolean, function, undefined, symbol 这七种类型,这种判断能帮助我们搞定一些问题;但是,很遗憾的一点是,typeof 在判断一个 object的数据的时候只能告诉我们这个数据是 object, 而不能细致的具体到是哪一种 object。

原理

其实,js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息👉

    000:对象 010:浮点数 100:字符串 110:布尔 1:整数

but, 对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的。

null:所有机器码均为0

undefined:用 −2^30 整数来表示

所以,typeof 在判断 null 的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待。

因此在用 typeof 来判断变量类型的时候,我们需要注意,最好是用 typeof 来判断基本数据类型(包括symbol),避免对 null 的判断。

缺陷

    无法区分 object 和 null,typeof null 的值为 object
typeof null // object
    无法判断具体为哪一种对象类型
typeof new Array() // object
typeof new String(123) // object
typeof new Number(1) // object

instanceof

instanceof 主要的作用就是判断一个实例是否属于某种类型,也可以判断一个实例是否是其父类型或者祖先类型的实例。

原理

其实 instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。

function new_instance_of(leftVaule, rightVaule) {
          
    
    let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
    leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
    while (true) {
          
   
    	if (leftVaule === null) {
          
   
            return false;	
        }
        if (leftVaule === rightProto) {
          
   
            return true;	
        } 
        leftVaule = leftVaule.__proto__ 
    }
}

缺陷

    无法判断 null、undefined 无法判断字面量形式数据的数据类型
1 instanceof Number // false
missy instanceof String // false

Object.prototype.toString.call

我们可以利用这个方法来对一个变量的类型来进行比较准确的判断

Object.prototype.toString.call({
          
   })              // [object Object]
Object.prototype.toString.call([])              // [object Array]
Object.prototype.toString.call(() => {
          
   })        // [object Function]
Object.prototype.toString.call(seymoe)        // [object String]
Object.prototype.toString.call(1)               // [object Number]
Object.prototype.toString.call(true)            // [object Boolean]
Object.prototype.toString.call(Symbol())        // [object Symbol]
Object.prototype.toString.call(null)            // [object Null]
Object.prototype.toString.call(undefined)       // [object Undefined]

Object.prototype.toString.call(new Date())      // [object Date]
Object.prototype.toString.call(Math)            // [object Math]
Object.prototype.toString.call(new Set())       // [object Set]
Object.prototype.toString.call(new WeakSet())   // [object WeakSet]
Object.prototype.toString.call(new Map())       // [object Map]
Object.prototype.toString.call(new WeakMap())   // [object WeakMap]```

总结

简单来说,我们使用 typeof 来判断基本数据类型是 ok 的,不过需要注意当用 typeof 来判断 null 类型时的问题,如果想要判断一个对象的具体类型可以考虑用 instanceof,但是 instanceof 也可能判断不准确,比如一个数组,他可以被 instanceof 判断为 Object。所以我们要想比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call 方法。

经验分享 程序员 微信小程序 职场和发展