先定义以下初始变量
ar num = 123; var str = 'abcdef'; var bool = true; var arr = [1, 2, 3, 4]; var obj = {name:'wenzi', age:25}; var func = function(){ console.log('this is function'); } var und = undefined; var nul = null; var date = new Date(); var reg = /^[a-zA-Z]{5,20}$/; var error= new Error();
1. 使用typeof检测
console.log( typeof num, // number typeof str, // string typeof bool, // boolean typeof arr, // object typeof obj, // object typeof func, // function typeof und, // undefined typeof nul, // object typeof date, // object typeof reg, // object typeof error // object );
从输出结果可以看出arr, json, nul, date, reg, error 全部被检测为object类型,其他的变量能够被正确检测出来。当需要变量是否是number, string, boolean, function, undefined类型时,可以使用typeof进行判断。其他引用类型以及null是判断不出类型的
2. 使用instanceof检测
首先instanceof能检测出继承
function Person(){} function Student(){} Student.prototype = new Person(); var John = new Student(); console.log(John instanceof Student); // true console.log(John instancdof Person); // true
其次可以判断引用类型
console.log( num instanceof Number, // false str instanceof String, // false bool instanceof Boolean, // false arr instanceof Array, // true--注意 arr instanceof Object, // true--注意 obj instanceof Object, // true--注意 func instanceof Function, // true und instanceof Object, // false nul instanceof Object, // false date instanceof Date, // true reg instanceof RegExp, // true error instanceof Error // true )
从结果可以看出instanceof不能判断值类型,但是引用类型可以,值得注意的是arr和obj在instanceof Object的时候的值都是true,这就导致判断是对象时不准确
原因是如下
[].__proto__ === Array.prototype // true Array.prototype.__proto__ === Object.prototype // true
3. 使用constructor检测
constructor本来是原型对象上的属性,指向构造函数。但是根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的
function Person(){} var Tom = new Person(); // undefined和null没有constructor属性 console.log( Tom.constructor==Person, num.constructor==Number, str.constructor==String, obj.constructor==Boolean, arr.constructor==Array, json.constructor==Object, func.constructor==Function, date.constructor==Date, reg.constructor==RegExp, error.constructor==Error ); // 所有结果均为true
表面上看很完美,但是有两个缺点
1).undefined和null没有constructor属性,所以判断时可能会报错--这就直接导致代码运行不下去了,所以只有在确定待判断的值不是undefined和null才能使用
2).由于constructor属性是可以变更的,也会导致检测出的结果不正确
4. 使用Object.prototype.toString.call -- 目前通用的办法
console.log( Object.prototype.toString.call(num), // '[object Number]' Object.prototype.toString.call(str), // '[object String]' Object.prototype.toString.call(bool), // '[object Boolean]' Object.prototype.toString.call(arr), // '[object Array]' Object.prototype.toString.call(obj), // '[object Object]' Object.prototype.toString.call(func), // '[object Function]' Object.prototype.toString.call(und), // '[object Undefined]' Object.prototype.toString.call(nul), // '[object Null]' Object.prototype.toString.call(date), // '[object Date]' Object.prototype.toString.call(reg), // '[object RegExp]' Object.prototype.toString.call(error) // '[object Error]' );
ECMA里规范定义了Object.prototype.toString的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于”[object Array]”的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。