JS判断数据类型

225 阅读2分钟

typeof

基础用法

typeof 1; // 'number'
typeof NaN; // 'number'
typeof '1'; // 'string'
typeof Symbol('test'); // 'symbol'
typeof true; // 'boolean'
typeof undefined: // 'undefined'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'
typeof console.log; // 'function'
typeof typeof null // 'object'

总结:typeof判断基础数据类型时,除了null,其他返回的值都是数据对应的类型。在判断引用数据类型的时候,除了函数,其他返回的值都是object。值得注意是,typeof 返回值的类型是string。

原理浅析

要想弄明白为什么typeof判断nullobject,需要从js底层如何存储变量类型来说,虽然说,这是JS设计的一个bug。
在JS最初的实现中,值是有一个表示类型的标签和实际数据值表示的。对象的类型标签是0。由于null代表的是空指针(大多数平台下值为0x00),因此null的类型标签是0,typeof null也因此返回object
js在底层存储变量的时候,会在变量的机器码的低位1-3存储其类型信息:

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

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

  • null所有的机器码均为0
  • undefined用−2^30 整数来表示表示
    所以在用typeof来判断变量类型的时候,我们需要注意,最好是用typeof来判断基本数据类型(包括symbol),避免对null的判断。

instanceof

instanceof可以正确判断对象的类型,是因为内部机制是通过判断对象的原型链中是不是能找到类型的prototype

基础用法

function A() {}
function B() {}
var a = new A();

a instanceof A; // true

手写instanceof

function myInstanceof(left, right){
    let prototype = right.prototype;
    left = left.__proto__;
    while(true) {
        if(left === null || left === undefined) {
            return false;
        }
        if(prototype === left) {
            return true;
        }
        left = left.__proto__
    }
}

实现分析:

  1. 获取类型的原型
  2. 获取对象的原型
  3. 然后一直循环判断队形的原型是否等于类型的原型,直到对象原型为null,因为原型链的终点是null

es6的 isArray

Array.isArray 只是用来判断是否为数组

Array.isArray([]); // true
Array.isArray({}); // false

Object.prototype.toString;

因为不同的数据类型中内置的toString方法是有区别的,所以我们借助Object原型上的toString来做统一处理

Object.prototype.toString.call(''); // '[object String]'
Object.prototype.toString.call(1); // '[object Number]'
Object.prototype.toString.call(true); // '[object Boolean]'
Object.prototype.toString.call(Symbol('test')); // '[object Symbol]'
Object.prototype.toString.call(null); // '[object Null]'
Object.prototype.toString.call(undefined); // '[object Undefined]'
Object.prototype.toString.call({}); // '[object Object]'
Object.prototype.toString.call([]); // '[object Array]'
Object.prototype.toString.call(console.log); // '[object Function]'
Object.prototype.toString.call(new Date()); // '[object Date]'

(function() {
    Object.prototype,toString.call(arguments);  // '[object Arguments]'
})();

封装一个获取变量类型的方法

function getType(varibale) {
    const typeStr = Object.prototype.toString.call(varibale);
    return typeStr.match(/\s+(\w+)/)[1];
}
getType({}); // Object
getType(''); // String