Javascript 因为各类各样的缘由,在判断一个变量的数据类型方面一直存在着一些问题,其中最典型的问题恐怕就是 typeof null
会返回 object
了吧。所以在这里简单的总结一下判断数据类型时常见的陷阱,以及正确的处理姿式。javascript
MDN 数据类型java
这里先谈一下 javascript 这门语言的数据类型。javascript 中有七种数据类型,其中有六种简单数据类型,一种复杂数据类型。git
Object
是惟一的复杂数据类型。 Object Array Function
这些引用类型值最终均可以归结为 Object
复杂数据类型。github
typeof
是用来检测变量数据类型的操做符,对一个值使用 typeof
操做符可能会返回下列某个字符串安全
function isObj(obj) { if (typeof obj === 'object') { return 'It is object'; } return 'It is not object'; }
这个函数的本意是想检测传入的参数是不是 Object 对象。可是这个函数实际上是很是不安全的。ecmascript
好比函数
var a = [1, 2, 3]; isObj(a); // 'It is object' var b = null; isObj(b); // 'It is object'
这样明显是不对的,由于 typeof []
和 typeof null
都是是会返回 'object'
的。测试
typeof [] // 'object'
上面说到了对一个数组使用 typeof 操做符也是会返回 'object'
,所以 typeof 并不能判断数组对象的类型prototype
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
《Javascript》高级程序设计 第五章第六节 基本包装类型
javascript 为了方便操做基本类型值,ECMAscript 提供了3个特殊的引用类型:Boolean、Number 和 String。
每当读取一个基本类型值的时候,后台就会建立一个对应的基本包装类型的对象,从而让咱们可以调用一些方法来操做这些数据。
var s1 = "some text"; var s2 = s1.substring(2);
上面的代码中,先建立了一个字符串保存在了变量 s1,字符串固然是基本类型值。可是在下一行中咱们又调用了 s1 的方法。咱们知道基本类型值不是对象,理论上它不该该拥有方法(但它们确实有方法)。其实,为了让咱们实现这种直观的操做,后台已经帮助咱们完成了一系列的操做。当咱们在第二行代码中访问 s1 变量时,访问过程处于读取模式,而在读取模式中访问字符串时,后台都会自动完成下列处理。
能够将以上三个步骤想像成是执行了下列代码
var s1 = new String("some text"); var s2 = s1.substring(2); s1 = null;
上面提到基本包装类,就是为了说明 instanceof 这个陷阱
var str = 'text'; str instanceof String; // false
原本我也是想固然的认为 str instanceof String
会使 str 变量处于读取模式,自动创建基本包装类。可是根据上述代码所体现表象来看,instanceof 运算符是直接访问的变量的原始值。
所以 instanceof 并不能用来判断五种基本类型值
这里先说一下,用 instanceof 判断 Array 类型基本上是很是ok的
var arr = [1, 2, 3]; arr instanceof Array; // true
可是 instanceof 却不能安全的判断 Object 类型,由于 Array 构造函数是继承自 Object 对象的,所以在 arr 变量上是能够访问到 Object 的 prototype 属性的。以下例所示:
var arr = [1, 2, 3]; arr instanceof Object; // true // 会返回 true ,是由于 Object 构造函数的 prototype 属性存在与 arr 这个数组实例的原型链上。
stack overflow 上有人作了实验,说是目前运算最快的判断变量类型的方式。
function cstor(variable) { var cst = variable.constructor; switch (cst) { case Number: return 'Number' case String: return 'String' case Boolean: return 'Boolean' case Array: return 'Array' case Object: return 'Object' } }
上面是一个判断变量类型的方法,工做的很是高效完美。可是用 constructor 判断变量类型有一个致命的缺陷,就是当检测 null 或者 undefined 类型的 constructor 属性时,js会报错!
也就是说下面代码会报错!
cstor(null); // 若传入 null 或者 undefined 做为参数时 // cstor 函数第一行就会报错,由于 null 和 undefined 根本就没有 constructor 属性
所以咱们在利用变量的 constructor 属性来判断变量类型时,必需要先保证变量有 不会是 null 或者 undefined。
改造以上函数以下:
function cstor(variable) { if (variable === null || variable === undefined) { return 'Null or Undefined'; } var cst = variable.constructor; switch (cst) { case Number: return 'Number' case String: return 'String' case Boolean: return 'Boolean' case Array: return 'Array' case Object: return 'Object' } }
因此说使用 constructor 来判断对象类型时要无时无刻不伴随着排除 null 和 undefined 的干扰,不然就会产生致命的问题,所以本人并不推荐。
Object.prototype.toString.call(variable)
用这个方法来判断变量类型目前是最可靠的了,它总能返回正确的值。
该方法返回 "[object type]"
, 其中type是对象类型。
Object.prototype.toString.call(null); // "[object Null]" Object.prototype.toString.call([]); // "[object Array]" Object.prototype.toString.call({}); // "[object Object]" Object.prototype.toString.call(123); // "[object Number]" Object.prototype.toString.call('123'); // "[object String]" Object.prototype.toString.call(false); // "[object Boolean]" Object.prototype.toString.call(undefined); // "[object Undefined]"
除了 Null
以外的这四种基本类型值,均可以用 typeof
操做符很好的进行判断处理。
typeof 'abc' // "string" typeof false // "boolean" typeof 123 // "number" typeof undefined // "undefined"
除了 Object.prototype.toString.call(null)
以外,目前最好的方法就是用 variable === null
全等来判断了。
var a = null; if (a === null) { console.log('a is null'); } // a is null
typeof []
会返回 object
所以明显是不可以用 typeof 操做符进行数组类型判断的。目前经常使用的方法有如下几种
万金油方法是一种。
Array.isArray([]); // true
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
所以能够检测一个对象的原型链中是否存在 Array 构造函数的 prototype 属性来判断是否是数组。
[] instanceof Array // true
typeof 和 instanceof 都不能安全的判断变量是不是 Object 对象。
目前判断变量是不是对象的最安全的方法就只有 Object.prototype.toString.call()
了。
做者博客:pspgbhu http://www.cnblogs.com/pspgbhu/
做者 Github:https://github.com/pspgbhu
欢迎转载,但请注明出处,谢谢!