3

typeof

用法示例

var arr = [];
typeof arr;    //'object'
typeof(arr);    //'object'

typeof实际上是一个一元运算符,因此可以用上述代码所示的两种用法。

typeof所支持的数据类型

clipboard.png

从上表可以看出,typeof支持的数据类型还是比较齐全的,除了俩比较特殊以外:

  • Null使用typeof返回object,这跟我们的认知还是有一定差距的,这是javascript的一个设计上的bug,ECMAScript 6中有提议修改此bug,但已经被否决了;不过只要加个逻辑非!运算符,就能把Null这种情况给排除了。
  • 除了function以外,其它具体的对象类型都无法判断出来。

typeof浏览器兼容性注意点

对正则表达式字面量的类型判断在某些浏览器中不符合标准:

typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1

IE 宿主对象是对象而不是函数

在 IE 6, 7 和 8 中,大多数的宿主对象是对象,而不是函数,例如:

typeof alert === 'object'

instanceof

用法示例

// 定义构造函数
function C(){} 
function D(){} 

var o = new C();

// true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof C; 

// false,因为 D.prototype不在o的原型链上
o instanceof D; 

o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true

instanceof是一个二元运算符。

instanceof总结

  • javascript中的原生对象以及用户的自定义对象基本上都能利用instanceof识别出来,除了NullUndefined
  • instanceof无法区分开同一原型继承链:
function A(){
    //...
}

function B(){
    //...
}

function C(){
    //...
}

var a = new A();
B.prototype = a;

var b = new B();
C.prototype = b;

var c = new C();

c instanceof A;    //true
c instanceof B;    //true
c instanceof C;    //true

Object.prototype.toString.call

用法示例

function type(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1);
}
type(1);    //"Number"
type("1");    //"String"
type(true);    //"Boolean"
type(undefined);    //"Undefined"
type(null);    //"Null"
type({});    //"Object"
type([]);    //"Array"
type(new Date);    //"Date"
type(/\d/);    //"RegExp"
type(function() {});    //"Function"

function Point(x, y) {
    //
}
type(new Point(1, 2));    //"Object"

用法解析

从以上用法示例可以看出,这个基于Object.prototype.toString.call封装好的函数用法跟typeof非常相似,但是在支持的数据类型上比typeof强多了,所有的javascript原生数据类型都能判断出来。遗憾的是,Object.prototype.toString.call也不是万能的方案:无法识别自定义的对象类型。
Object.prototype.toString.call实际上是返回这样形式的值:

Object.prototype.toString.call(1);    //'[object Number]'
Object.prototype.toString.call('1');    //'[object String]'

因此只要用slice方法把数据类型“切”出来就成了。

constructor(构造函数)

用法示例

/*
* 获取对象构造函数名称
*/
function getConstructorName(obj){
    return obj && obj.constructor && obj.constructor.toString().match(/function\s*([^(]*)/)[1]; //利用obj && obj.constructor来判断null和undefined
}

用法解析

这是一种非常巧妙的判断数据类型的方法——利用构造函数判断数据类型,这是基于javascript的特性/规范:

  • 对象的构造函数名就是该数据类型。
  • NullUndefined外,所有的数据类型都是/可以转化为对象,而如果是对象,就肯定有构造函数。

特性

  1. 因为NullUndefined没有构造函数,因此不能用此方法来判断。
  2. 由于同一条原型继承链上的各个对象的构造函数都不一样,因此,此方法可以区分开继承链上的各个自定义数据类型。
function A(){
    //...
}

function B(){
    //...
}

function C(){
    //...
}

var a = new A();
B.prototype = a;

var b = new B();
C.prototype = b;

var c = new C();

getConstructorName(a);    //A
getConstructorName(b);    //B
getConstructorName(c);    //C

总结

以上这四种方法都有不同程度的缺陷,如果从实用性的角度来考虑,可以综合一下:

function type(obj) {console.dir(obj);
  if(!obj) {
    return Object.prototype.toString.call(obj).slice(8, -1);
  }
  return obj.constructor.toString().match(/function\s*([^(]*)/)[1];
}
var t = type(1) // t==="number"
var t = type(new Number(1)) // t==="number"
var t = type("abc") // t==="string"
var t = type(new String("abc")) // t==="string"
var t = type(true) // t==="boolean"
var t = type(undefined) // t==="undefined"
var t = type(null) // t==="null"
var t = type({}) // t==="object"
var t = type([]) // t==="array"
var t = type(new Date) // t==="date"
var t = type(/\d/) // t==="regexp"
var t = type(function(){}) // t==="function"

参考资料

typeof - JavaScript | MDN
instanceof - JavaScript | MDN


array_huang
10.4k 声望6.6k 粉丝