JavaScript类型判断

typeof、prototype、instanceof、constructor方法比较

typeof

我们最常见的是typeof,通常我们会看到

1
console.log(typeof('mamba'))  //string

这种写法,但是typeof可是一个一元运算符,就跟加减乘除一样

1
console.log(typeof 'mamba')  //string

《JavaScript权威指南》中对typeof的介绍:

typeof 是一元操作符,放在其单个操作数的前面,操作数可以是任意类型。返回值为表示操作数类型的一个字符串。

在 ES6 前,JavaScript 共六种数据类型,分别是:

1
Undefined、Null、Boolean、Number、String、Object

然而当我们使用 typeof 对这些数据类型的值进行操作的时候,返回的结果却不是一一对应,分别是:

1
undefined、object、boolean、number、string、object

注意以上都是小写的字符串。Null 和 Object 类型都返回了 object 字符串。
尽管不能一一对应,但是typeof却能检测出函数类型:

1
2
function a() {}
console.log(typeof a) //function

所以 typeof 能检测出六种类型的值,但是,除此之外 Object 下还有很多细分的类型呐,如 Array、Function、Date、RegExp、Error 等。

例如:

1
2
3
4
var date = new Date();
var error = new Error();
console.log(typeof date); // object
console.log(typeof error); // object

返回的都是 object ,所以就要用Object.prototype.toString来检测了

Object.prototype.toString(通用但很繁琐)

当 toString 方法被调用的时候,下面的步骤会被执行:

  • 如果 this 值是 undefined,就返回 [object Undefined]
  • 如果 this 的值是 null,就返回 [object Null]
  • 让 O 成为 ToObject(this) 的结果
  • 让 class 成为 O 的内部属性 [[Class]] 的值
  • 最后返回由 “[object “ 和 class 和 “]” 三个部分组成的字符串

通过规范,我们至少知道了调用 Object.prototype.toString 会返回一个由 “[object “ 和 class 和 “]” 组成的字符串,而 class 是要判断的对象的内部属性。

让我们写个 demo:

1
2
3
4
5
console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(null)) // [object Null]

var date = new Date();
console.log(Object.prototype.toString.call(date)) // [object Date]

1
2
3
4
5
6
7
8
9
10
11
var number = 1;            // [object Number]
var string = '123'; // [object String]
var boolean = true; // [object Boolean]
var und = undefined; // [object Undefined]
var nul = null; // [object Null]
var obj = {a: 1} // [object Object]
var array = [1, 2, 3]; // [object Date]
var date = new Date(); // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g; // [object RegExp]
var func = function a(){}; // [object Function]

除以上11种还有

1
2
3
4
5
6
7
console.log(Object.prototype.toString.call(Math)); // [object Math]
console.log(Object.prototype.toString.call(JSON)); // [object JSON]

function a() {
console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
}
a();

既然有了 Object.prototype.toString 这个神器!那就让我们写个 type 函数帮助我们以后识别各种类型的值吧!
写一个 type 函数能检测各种类型的值,如果是基本类型,就使用 typeof,引用类型就使用 toString。此外鉴于 typeof 的结果是小写,我也希望所有的结果都是小写。

  • 考虑兼容性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var class2type = {};

    // 生成class2type映射
    "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
    class2type["[object " + item + "]"] = item.toLowerCase();
    })

    function type(obj) {
    // 一箭双雕
    if (obj == null) {
    return obj + "";
    }
    return typeof obj === "object" || typeof obj === "function" ?
    class2type[Object.prototype.toString.call(obj)] || "object" :
    typeof obj;
    }
  • 不考虑兼容性

    1
    2
    3
    function type(val){
    return Object.prototype.toString.call(val).split(' ')[1].split(']')[0].toLowerCase();
    }

isFunction

有了 type 函数后,我们可以对常用的判断直接封装,比如 isFunction:

1
2
3
function isFunction(obj) {
return type(obj) === "function";
}

数组

jQuery 判断数组类型,旧版本是通过判断 Array.isArray 方法是否存在,如果存在就使用该方法,不存在就使用 type 函数。

1
2
3
var isArray = Array.isArray || function( obj ) {
return type(obj) === "array";
}

待续···

1
2
3
4
5
6
var a = "iamstring.";
var b = 222;
var c= [1,2,3];
var d = new Date();
var e = function(){alert(111);};
var f = function(){this.name="22";}

判断已知对象类型的方法:instanceof

1
2
3
4
alert(c instanceof Array) ---------------> true
alert(d instanceof Date) ---------------> true
alert(f instanceof Function) ------------> true
alert(f instanceof function) ------------> false
  • 注意:instanceof后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。

    根据对象的constructor判断:constructor
    1
    2
    3
    alert(c.constructor === Array) ----------> true
    alert(d.constructor === Date) -----------> true
    alert(e.constructor === Function) -------> true
  • 注意: constructor 在类继承时会出错

例子:

function A(){};
function B(){};
A.prototype = new B(); //A继承自B
var aObj = new A();
alert(aobj.constructor === B) -----------> true;
alert(aobj.constructor === A) -----------> false;
而instanceof方法不会出现该问题,对象直接继承和间接继承的都会报true:
alert(aobj instanceof B) ----------------> true;
alert(aobj instanceof B) ----------------> true;
言归正传,解决construtor的问题通常是让对象的constructor手动指向自己:
aobj.constructor = A; //将自己的类赋值给对象的constructor属性
alert(aobj.constructor === A) -----------> true;
alert(aobj.constructor === B) -----------> false; //基类不会报true了;