类型判断的方法 - Object.prototype.toString是最优解
Array.isArray()
ES5,低版本浏览器不支持。只有Array有这个方法。
typeof
无法判断出array与null,两个返回结果都是object。
instanceof
问题1:
1 | var num = 1 |
如果是直接创建的原始类型,不instanceof其构造函数。当然,array、object等引用类型不受影响。
问题2:
1 | // index.html |
1 | a.html |
跨iframe对象无法正常判断。这是因为跨iframe实例化的对象彼此不共享原型链。如果是a instanceof window.frames[0].Array
或a.constructor === window.frames[0].Array
,那么结果就是true了。
constructor
与instanceof的问题2相同。
[正确]Object.prototype.toString()
1 | Object.prototype.toString.call(10) // [object Number] |
Object.prototype.toString.call()为什么能返回这样类型的字符串?
ECMA-262:
Object.prototype.toString.call() When toString method is called, the following steps are taken:
- Get the [[Class]] prototype of the object.
- Computed a string value by concatenating the three things “[object”, Result (1), and “]”.
- Return result (2).
即取得一个对象的内部属性[[Class]],然后依据这个属性返回一个类似“[object String]”的字符串作为结果([[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取到任何对象的内部属性[[Class]]。
ECMA标准中对Array的描述:
new Array([ item 0[, item 1, [,…]] ])
The [[Class]] property of the newly constructed object is set to “Array”.
原文与参考
常用类型的判断
object
1 | _.isObject = function (obj) { |
underscore将function和object都算作对象,!!obj为了除去null。
这里需要注意顺序,先判断function,再判断Object。否则,在obj为null的情况下,typeof obj !== ‘function’,判断为false直接返回,不再继续执行,因此执行不到!!obj步骤。
可以用Object.prototype.toString()直接判断的类型
1 | _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function (name) { |
arguments
IE < 9下对arguments调用Object.prototype.toString()返回结果为[object Object],而非[object Arguments],我们可以用该元素是否含有callee属性来判断,arguments.callee能返回当前arguments所在的函数。
1 | if (!_.isArguments(arguments)) { |
DOM元素
不为空且nodeType属性为1。
1 | _.isElement = function (obj) { |
NaN
Object.prototype.isString.call(NaN)返回[object Number]。
1 | _.isNaN = function (obj) { |
原生isNaN会做一个强制类型转换,先将非Number类型的值转换toNumber,然后看返回值是不是NaN。而underscore只希望判断数值的NaN,因此加上_.isNumber判断。