关于javascript:深入-JS-类型检测原理和模拟实现

47次阅读

共计 4387 个字符,预计需要花费 11 分钟才能阅读完成。

原文地址

掘金

求 star

思维导图

JS 中的类型

  • 根本类型,number,string,null,undefined,Boolean,es6 新增的 symbol,es11
    中的 bigint 总共 7 种根本类型
  • 援用类型:object,function

    数据类型的检测形式

    数据类型的检测的办法中共有四种typeof, instanceof, Object.prototype.toString.call(), constructor

一、typeof

typeof 检测原理是:在计算机底层 依据 js 数据类型的二进制的值进行检测的

  • typeof 检测类型后的返回值是一个 字符串,ES5 中对于一个为定义的变量判断类型也会抛出字符串undefined,而不是报错。然而用 let, const 申明的变量也能会导致暂时性死区,抛出 ReferenceError

    typeof undefined    //"undefined"
    typeof a // "undefined"
    typeof b // "ReferenceError" 
    let b
    
    typeof 12   //"number"
    typeof NaN  //"number"
    typeof ''//"string"typeof 1n    //"bigint"typeof function(){}     //"function"
  • (毛病) typeof 能够检测除了 null 类型以外的数据型。null 被检测成 object 这是一个历史遗留的 bug。
  • (毛病) typeof 不能检测出具体的 object 类型,因为对象类型的二进制结尾都是 000。比方 typeof [] //"object" 检测数组,正则,日期等。
  • 其余类型的二进制,000 对象,00000... null,1 整数,010 浮点数,100 字符串,110 布尔值,-2^30 undefined
typeof {}   // "object"
typeof []   // "object"
typeof /^/  // "object"

typeOf 判断函数为什么能够判断出是 function 类型而不是 object

JS 中尽管函数也是对象,然而 typeOf 判断函数是会调用 call 办法来判断。所以能判断出function

思考:typeof null 检测进去的后果为什么是 object

typeof 是依据二进制值来判断数据类型的,null 的二进制值是 000,而 object 类型的二进制值都是 000 结尾的,所以 typeof 检测 null 是也被检测成 object,这是一个历史里留下来的 bug

思考:0.1 + 0.2 !== 0.3 成立起因

二、冒名顶替的 instanceof

instanceof 检测机制是:判断右侧的类型是否呈现在左侧实例的原型链上,呈现了返回的后果就是 true 否则是 false

  • instanceof 判断返回的后果是一个 Boolean 值。
  • instanceof 是用来检测以后的实例是否属于某个类的。能够用来解决 typeof 无奈检测具体的对象类型的问题。

    let ary = []
    console.log(ary instanceof Array)   // true
    
    let reg = /^/
    console.log(reg instanceof RegExp)  // true
  • (毛病) 只有以后类呈现在实例的原型链上检测的后果就是 true,那么 Object 类型检测的后果永远都是 true,如果实例的原型被批改了,即便检测的后果是 true,也是不精确的。
  • (毛病) instanceof 不能检测根本数据类型。

    // 呈现在原型链上的类型都被判断成 true
    let ary = []
    console.log(ary instanceof Object)   // true
    
    function fn(){}
    fn.prototype = Array.prototype  // 原型被批改了
    let f = new fn()
    console.log(f instanceof Array) // true
    console.log(f instanceof Function) // false
    
    // 不能检测根本数组类型
    console.log(1 instanceof Number)    //false
    console.log('' instanceof String)   //false
    console.log(false instanceof Boolean)   //false

    思考,模仿实现 instanceof

    思路:依据左侧实例的原型链上是否呈现右侧的类型进行判断后果。即 实例.__proto__ === 类.prototype,则是 true 否则是 false。对原型和原型链不相熟的能够看 面试 | 你不得不懂得 JS 原型和原型链。

    function _instanceof(example, classP) {let proto = Object.getPrototypeOf(example),
          classPrototype = classP.prototype
      while (true) {if (proto === classPrototype) {return true}
          if (proto === null) {return false}
          proto = Object.getPrototypeOf(proto)
      }
    
    _instanceof([], Array)  //true
    _instanceof('', Array)  // false
    _instanceof('', Object) // true

三、冒名顶替的 constructor

instanceof 检测机制是:constructor 寄存的就是构造函数自身,通过寄存的构造函数来检测类型。不相熟 constructor的也能够看 面试 | 你不得不懂得 JS 原型和原型链。

  • constructor 能够检测根本类型,这点比 instanceof 好用

    let ary = []
    ary.constructor === Array   // true,ary.constructor ==> Array.prototype.constructor
    ary.constructor === String  // false
    ary.constructor === Object  // false
    
    let a = 1
    a.constructor === Number    // true
    
    let s = ''
    s.constructor === String    // true
  • (毛病) constructorinstanceof 有一样的缺点,就是 constructor 能够被批改也就是重定向

    Number.prototype.constructor = 'abc'
    let a = 1
    a.constructor === Number    // false

四、Object.prototype.toString.call(),规范检测类型

检测机制是:利用 Object.prototype.toString 返回实例所属类的信息,通过扭转 toString 中的 this 指向来返回指定参数的类型。

  • Object.prototype.toString 返回的格局固定是 '[object xxx]',能够检测任意类型

    Object.prototype.toString.call(1)       //"[object Number]"
    Object.prototype.toString.call('')      //"[object String]"Object.prototype.toString.call(null)        //"[object Null]"Object.prototype.toString.call(undefined)       //"[object Undefined]"Object.prototype.toString.call(Symbol())        //"[object Symbol]"Object.prototype.toString.call([])          //"[object Array]"Object.prototype.toString.call(function(){})        //"[object Function]"Object.prototype.toString.call({})      //"[object Object]"
  • (毛病) 不能间接提取出数据类型,还须要转变才拿到间接的类型

五、其余快捷判断形式

isNumber(), isNaN(), Array.isArray()。。。

六、封装一个万能的检测办法 toType()

1. jQuery 中的类型检测

(function () {
    // jquery 中的 toType
    let class2type = {},
        toString = class2type.toString

    // 设定类型映射表
    let arrType = ['Number', 'String', 'Boolean', 'Symbol', 'Array', 'Date', 'Error', 'RegExp', 'Function', 'Object']
    arrType.forEach(item => {class2type[`[object ${item}]`] = item.toLowerCase()});

    function toType(checkType) {if (checkType === null || checkType == undefined) {return checkType + ''}
        return typeof checkType == 'object' || typeof checkType == 'function' ? class2type[toString.call(checkType)] : typeof checkType
    }
    window.toType = toType
})()

toType(1)   //"number"
toType('')  //"string"toType(null)    //"null"toType(undefined)   //"undefined"toType({})  //"object"toType(function(){})    //"function"toType([])  //"array"

实质上还是利用了Object.prototype.toString.call()

2. 自封装一个更简略的 selfType()

(function () {function selfType(checkType) {let res = {}.toString.call(checkType).split('')[1].split(']')[0].toLowerCase() // 能够应用正则
        return res
    }
    window.selfType = selfType
})()

selfType('')        //"string"selfType(1)     //"number"selfType(null)      //"null"selfType(undefined)     //"undefined"selfType(function(){})     //"function"selfType({})    //"object"

正文完
 0