JS数据类型检测

91 阅读2分钟

数据类型检测

1. typeof

typeof 是直接在计算机底层基于数据类型的二进制值来检测类型的。

对于原始类型,除了 null 类型,其他都能显示正确的类型。

对于 null 作为基本数据类型为什么会返回 object 是一个历史遗留Bug,在JS中,数据类型二进制前三位为 000 会被判断为 object 类型,而 null 底层的二进制为全0,故前三位肯定也是 000,所以被判断为 object

对于对象(普通对象/数组对象/正则对象/日期对象)类型,除了函数都会显示 object 类型,所以 typeof 并不能很精确判断的对象类型的数据。

typeof []          // "object"
typeof {}          // "object"
typeof console.log // "function"

2. instanceof

instanceof 初始被设计出来是用来检测某一个实例是否属于某一个类的,后续引申出用来检测数据类型,所以也并不能判断所有的数据类型(不能检测基本类型。

如果我们想判断一个 对象 的正确类型,这时候可以考虑使用 instanceof,因为内部机制是通过原型链来判断的,只要当前类出现实例的原型链上,结果就为 true

由于我们可以修改原型的指向,所以检测出来的结果不一定准确。

了解了 instanceof 的机制,在后面的章节中我们也会自己去实现一个 instanceof

function instanceOf(example, classFunc) {
    let classFuncPrototype = classFunc.prototype,
    proto = Object.getPrototypeOf(example)

    while (true) {
        if (!proto) {
            // Object.prototype.__proto__ 为 null
            return false
        }

        if (proto === classFuncPrototype) {
            return true
        }

        proto = Object.getPrototypeOf(proto)
    }
}

3. constructor

可以通过 constructor 来判断数据的类型,但是除了null和undefined,因为他们不是由对象构建。

需要注意,如果改变类的 constructorconstructor 就不能用来判断数据类型了。

console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true

4. Object.prototype.toString.call()

检测数据类型的最标准的方法。

Object.prototype.toString() 方法不是转换为字符串,而是返回当前实例所属类的信息。故让 Object.prototype.toString() 指向,并把 this 指向为要检测的值,就能返回当前值所属类的信息。

5. JQ封装的类型检测方法

var class2type = {}
var toString = class2type.toString // Object.prototype.toString

["Boolean", "Number", "String", "Function", "Array", "Date",
 "RegExp", "Object", "Error", "Symbol"].forEach(name => {
    class2type[`[object ${name}]`] = name.toLowerCase()
})

function toType() {
    if (obj == null) {
        return obj + ""
    }

    return typeof obj === "object" || typeof obj === "function" ?
        class2type[toString.call(obj)] || 'object' :
        typeof obj 
}