美文网首页
js类型判断及实现原理

js类型判断及实现原理

作者: 李栋盛 | 来源:发表于2020-05-18 18:09 被阅读0次

    typeof 实现原理

    typeof 一般被用于判断如number, string, object, boolean, function, undefined, symbol 这些类型,在非object类型数据时,type of返回的结果比较清楚。但是 在判断object类型数据的时候只能告诉我们这个数据的类型是 object,而不能告诉我们具体是哪一种object

    那么,typeof是如何判断这些类型的呢?其实是直接去判断了js底层存储变量类型的信息:

    在 js 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,会在变量的机器码的低位1-3位存储其类型信息,如:

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

    对于 undefinednull 来说,这两个值的信息存储是有点特殊的:

    • null:所有机器码均为0
    • undefined:用 −2^30 整数来表示

    所以一个js的遗留bug原因我们也知道了,就是 typeof 在判断 null 的时候出现问题,由于 null 的所有机器码均为0,因此直接被当做了对象来看待

    因此,在使用typeof判断类型时,最好使用用来判断基本数据类型,避免对null进行判断,object由于不够准确,也不推荐使用。

    Object.prototype.toString.call()

    如果我们想获得一个变量的正确类型,可以通过 Object.prototype.toString.call(xx)。这样我们就可以获得类似 [object Type] 的字符串

    Object.prototype.toString.call(1) // "[object Number]"
    
    Object.prototype.toString.call('hi') // "[object String]"
    
    Object.prototype.toString.call({a:'hi'}) // "[object Object]"
    
    Object.prototype.toString.call([1,'a']) // "[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(1)) // "[object Symbol]"
    

    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__ 
        }
    }
    

    要全部了解instanceof实现原理,还需要知道 JavaScript 的原型继承原理

    原型链.png

    我们知道每个 JavaScript 对象均有一个隐式的 __proto__ 原型属性,而显式的原型属性是 prototype,只有 Object.prototype.__proto__ 属性在未修改的情况下为 null 值。根据图上的原理,我们来梳理上面提到的几个有趣的 instanceof 使用的例子。

    • Object instanceof Object

    由图可知,Object 的 prototype 属性是 Object.prototype, 而由于 Object 本身是一个函数,由 Function 所创建,所以 Object.proto 的值是 Function.prototype,而 Function.prototype 的 proto 属性是 Object.prototype,所以我们可以判断出,Object instanceof Object 的结果是 true 。用代码简单的表示一下

    leftValue = Object.__proto__ = Function.prototype;
    rightValue = Object.prototype;
    // 第一次判断
    leftValue != rightValue
    leftValue = Function.prototype.__proto__ = Object.prototype
    // 第二次判断
    leftValue === rightValue
    // 返回 true
    
    • Foo instanceof Foo

    Foo 函数的 prototype 属性是 Foo.prototype,而 Foo 的 proto 属性是 Function.prototype,由图可知,Foo 的原型链上并没有 Foo.prototype ,因此 Foo instanceof Foo 也就返回 false 。

    leftValue = Foo, rightValue = Foo
    leftValue = Foo.__proto = Function.prototype
    rightValue = Foo.prototype
    // 第一次判断
    leftValue != rightValue
    leftValue = Function.prototype.__proto__ = Object.prototype
    // 第二次判断
    leftValue != rightValue
    leftValue = Object.prototype = null
    // 第三次判断
    leftValue === null
    // 返回 false
    
    • Foo instanceof Object
    leftValue = Foo, rightValue = Object
    leftValue = Foo.__proto__ = Function.prototype
    rightValue = Object.prototype
    // 第一次判断
    leftValue != rightValue
    leftValue = Function.prototype.__proto__ = Object.prototype
    // 第二次判断
    leftValue === rightValue
    // 返回 true 
    
    • Foo instanceof Function
    leftValue = Foo, rightValue = Function
    leftValue = Foo.__proto__ = Function.prototype
    rightValue = Function.prototype
    // 第一次判断
    leftValue === rightValue
    // 返回 true 
    

    总结

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

    参考文章:https://juejin.im/post/5b0b9b9051882515773ae714

    相关文章

      网友评论

          本文标题:js类型判断及实现原理

          本文链接:https://www.haomeiwen.com/subject/czdpohtx.html