本文深入解析JavaScript中检测数据类型的多种方法。对比typeof、Object.prototype.toString.call、constructor属性以及instanceof的适用场景与局限性,重点说明typeof对null和NaN的检测缺陷,以及constructor被篡改时的安全风险。同时介绍Array.isArray的兼容性问题和jQuery提供的辅助函数,帮助开发者在不同场景下选择严谨的检测方案。
本文通过具体实例详细阐述JavaScript中检测数据类型的各种方法,旨在为开发者提供实用的参考与对比分析。
JavaScript数据类型分类
在JavaScript语言体系中,数据类型主要分为值类型和引用类型两大类。
值类型包括布尔型(Boolean)、数值型(Number)、字符串型(String)、空值(Null)以及未定义(Undefined)。
引用类型则涵盖对象(Object)、函数(Function)、数组(Array)、日期(Date)和正则表达式(RegExp)等复杂数据结构。
typeof检测方法的局限性
接下来探讨第一种常用的检测方式:使用typeof操作符。
console.log(typeof undefined)//'undefined'
console.log(typeof null) // object
console.log(typeof true) //'boolean'
console.log(typeof 123) //'number'
console.log(typeof NaN) //'number'
console.log(typeof "abc") //'string'
console.log(typeof function() {}) //'function'
var arr=[];
console.log(typeof {}) //'object'
console.log(typeof arr)//'object'
通过上述示例可以看出,单纯依赖typeof进行检测存在明显的严谨性问题。
具体而言,null值被typeof检测为object。这是因为null表示一个空对象指针,而在ECMAScript早期设计中存在这一遗留特性,导致typeof null返回object。
这是JavaScript设计不严谨的另一种表现。此外,数组也被typeof检测为对象,因此这种方式无法准确区分普通对象与数组,显得不够严谨。
Object.prototype.toString.call()检测法
第二种检测方式是利用Object.prototype.toString.call()方法。
console.log(toString.call(undefined) ) // '[object Window]''
console.log(toString.call(null) ) // '[object Window]'
console.log(toString.call(true) ) // '[object Boolean]'
console.log(toString.call(123) ) // '[object Number]'
console.log(toString.call(NaN) ) // '[object Number]'
console.log(toString.call("abc") ) // '[object String]'
console.log(toString.call(function() {})) // '[object Function]'
var arr=[];
console.log(toString.call({}) ) // '[object Object]'
console.log(toString.call(arr) ) // '[object Array]'
从测试结果来看,除了undefined和null这两个特殊值外,其他类型的检测结果都相对严谨准确。
需要注意的是,toString()函数是window对象的一个不可枚举函数,它继承自Object原型。
该方法还可以采用以下写法进行调用:
window.toString.call('hello'); // "[object String]"
Object.prototype.toString.call('hello'); // "[object String]"
constructor属性检测法
第三种检测方式是基于constructor属性。
console.log('haha'.constructor == String); // true
console.log([].constructor === Array); // true
console.log({}.constructor === Object); // true
console.log(true.constructor === Boolean); // true
var a = 111; // 此处必须要用变量来代表数字,不然会报错,从这也能看出来js是一门不严谨的语言
console.log(a.constructor === Number); // true
如果我们通过修改实例的constructor指向其他构造函数,就会破坏其原始类型标识,导致检测结果不安全,因此不推荐使用此方法。具体代码示例如下:
var AAA = function(){}; // 定义一个AAA对象
AAA.prototype = {
say:function() {
alert('hello');
}
}
var arr1 = new Array(); // 定义一个数组
arr1.constructor = function AAA(){}; // 这里可以改变实例的constructor。
arr1.__proto__ = AAA.prototype; // 此处改变了原型链
console.log(arr1.constructor); // AAA
console.log(arr1 instanceof AAA); // true 原型链已经改变,arr1 已经不属于Array了。
console.log(arr1 instanceof Array); // false
// 下面我们来让AAA的原型链连到 Array上
AAA.prototype.__proto__ = Array.prototype;
console.log(arr1 instanceof Array); // true
instanceof运算符检测法
第四种检测方式是使用instanceof运算符。
该运算符用于检测某个对象是否为另一对象的实例。
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log('haha' instanceof String); // false
console.log(true instanceof Boolean); // false
console.log(1 instanceof Number); // false
前两个测试结果为true,而后续基本类型均为false,这说明使用A instanceof B进行检测的前提条件是A和B都必须是对象。通过以下示例可以清晰看出这一限制:
var a = new Number(1);
var b = new String('haha');
var t = new Boolean(true);
console.log(a instanceof Number); // true
console.log(b instanceof String); // true
console.log(t instanceof Boolean); // true
这种方式同样存在安全隐患,后续将对此进行阐述。关于instanceof与isPrototypeOf的区别,将在后续内容中进一步探讨。
Array.isArray()及jQuery辅助方法
此外,还有一种专门用于检测数组的方法:Array.isArray()。
console.log(Array.isArray([])); // true
该方法存在浏览器兼容性问题,在IE8及更低版本的浏览器中不被支持。
针对兼容性问题,jQuery库也提供了一些解决方案。
jQuery.isArray():是否为数组。
jQuery.isEmptyObject():是否为空对象(不含可枚举的属性)。
jQuery.isFunction():是否为函数。
jQuery.isNumeric():是否为数字。
jQuery.isPlainObject():是否为使用“{}”或“new Object”生成的对象,而不是浏览器原生提供的对象。
jQuery.isWindow():是否为window对象。
jQuery.isXMLDoc():判断一个DOM节点是否处于XML文档之中。
总结部分对上述检测方法进行归纳。
通过上述几种检测方式的分析,我们可以得知,在不同场景下选择合适的检测方法,是一种行之有效的解决方案。
Number类型的有穷检测isFinite()
拓展阅读部分介绍Number类型中的特殊检测方法。
在Number类型中,还有一种检测有穷数字的方法称为isFinite()。例如,任何数字除以0都会得到无穷大(Infinity或-Infinity),这些值以及非数字(NaN)在isFinite()检测中都会返回false。
console.log(3/0); // Infinity
console.log(-3/0); // -Infinity
console.log(isFinite(3/0)); // false
console.log(isFinite(-3/0)); // false
console.log(isFinite(NaN)); // false
console.log(isFinite('haha')); // false
console.log(isFinite(true)); // true 在这里 true 被转换成了数字 1
console.log(isFinite(false)); // true 在这里 false 被转换成了数字 0
感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码的运行效果。
更多关于JavaScript相关内容可查看本站专题:《JavaScript操作DOM技巧总结》、《JavaScript页面元素操作技巧总结》、《JavaScript事件相关操作与技巧大全》、《JavaScript查找算法技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript错误与调试技巧总结》。
希望本文所述的检测方法对大家学习JavaScript程序设计有所帮助。