JS类型判断---typeof, constructor, instanceof, toString

4,552 阅读4分钟

JS中的数据类型

js中,根据存储的方式不同(参见文末连接), 数据可以划分为以下两大类型:

  • 原始类型

    string, number, boolean, undefined, null, symbol

  • 引用类型

    Object (Array, Function, RegExp, Date)

数据类型判断

判断数据的所属类型此处列举四种方法,并对每种方法使用的范围以及限制进行说明.如果对原型链还不熟悉的同学,请先阅读相关的原型链知识(见文末)

  1. typeof

    typeof 一般仅用于判断原始类型(不包含null),返回值为该类型的字符串

    console.log(typeof 'str');  // string
    console.log(typeof 1);      // number
    console.log(typeof true); // boolean
    console.log(typeof undefined); // undefined
    console.log(typeof Symbol()); // symbol
    

    注意: typeof不能用于判断原始类型中的null以及引用类型object,结果都会返回字符串object(Function类型除外,结果会返回function,但在在 IE 6, 7 和 8 上则返回object)

    console.log(typeof null);  // object
    console.log(typeof {}); // object
    console.log(typeof alert); // function
    console.log(typeof []); // object
    console.log(typeof new RegExp()); // object
    console.log(typeof new Date()); // object
    
  2. contructor

    constructor主要是利用原型上的prototype.constructor指向实例的构造函数来进行判断的

    先定义一个构造函数Animal, 并new一个实例dog

    const Animal = function (name) {this.name = name};   // 声明一个构造函数
    let dog = new Animal('dog'); // 生成实例dog
    

    声明Animal函数的同时js会在Animal上挂载一个prototype对象,同时在prototype对象上会自动生成一个constructor属性并指向构造函数Animal,相当于:
    Animal.prototype.constructor === Animal // true ,根据原型链的查找原则, console(dog.prototype) // Animal 所以利用构造函数原型上的constructor属性可以判断当前实例是否为当前构造函数的实例,进而确定数据所属类型:

    console.log('1'.constructor === String);  // true
    console.log(new Number(1).constructor === Number); // true
    console.log(true.constructor === Boolean); // true
    console.log(alert.constructor === Function); // true
    console.log([].constructor === Array); // true
    console.log(new Date().constructor === Date); // true
    

    注意:

    1. null, undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
    2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

    constructor 判断类型的限制过多且不准确,容易出错,少用,或者不用!

  3. instanceof

    typeofconstructor 不同, instanceof一般用于判断引用类型,返回值为布尔值, 例如:

    [] instanceof Array // true

    instanceof 是通过判断当前实例的原型与构造函数的原型是否为同一对象,进而确定当前数据的类型,这样讲或许不够明了,我们简单实现一下 instanceof

    const self_instanceof = function (instance, constructor) {
        let instance_proto = instance.__proto__;
        let constructor_proto = constructor.prototype;
    
        while(true) {
            // 找到终点返回false
           if (instance_proto === null) {return false};
           // 找到返回true
           if (instance_proto === constructor_proto) {return true};
            // 当实例与构造函数原型不相同, 沿着原型链继续向上查找
            instance_proto = instance_proto.__proto__;
        }
    }
    console.log([] instanceof Array)   // true
    console.log(self_instanceof([], Array))  // true
    

    当一个页面存在多个iframe时,也就是存在多个全局变量window,instanceof的判断会被来自不同的iframe的数据所干扰,导致不可信

    假设:页面pageA 通过iframe内嵌了页面pageB, 此时pageB传递了一个数组 let arrB = []到页面 pageA, 若在pageA使用instanceof判断数组arrB会出现 arrB instanceof Array // false 主要原因是因为 arrB 是由pageB上的Array构造出来的

    要避免这种问题可以使用Es6提供的数组静态方法 Array.isArray, 或者我们即将提到的toString方法进行判断
    Array.isArray(arrB) // true

  4. toString

    toStringObject.prototype上的一个方法, 常用方式为 Object.prototype.toString.call(target)
    返回值是 [object 类型]字符串,该方法基本上能判断所有的数据类型(自定义数据类型除外)

    // 定义判断类型函数
    let getType = target => Object.prototype.toString.call(target)
    
    console.log(getType('')); // [object String]
    console.log(getType(2)); // [object Number]
    console.log(getType(true)); // [object Boolean]
    console.log(getType(undefined)); // [object Undefined]
    console.log(getType(null)); // [object Null]
    console.log(getType(Symbol())); // [object Symbol]
    console.log(getType({})); // [object Object]
    console.log(getType([])); // [object Array]
    console.log(getType(alert)); // [object Function]
    console.log(getType(new RegExp())); // [object RegExp]
    console.log(getType(new Date())); // [object Date]
    

    该方法准确稳定,推荐使用

以上为类型判断的一些见解, 有不当之处, 还请大佬们指正!

相关知识点文章请参考:

详细图解 JavaScript 内存空间
JS原型链与继承别再被问倒了