本文总结了JavaScript中检测数据类型的三种主要方式:typeof、instanceof以及Object.prototype.toString。详细分析了各自的工作原理、局限性及适用场景,并通过代码示例展示了如何基于Object.prototype.toString实现is系列类型判断函数,帮助开发者根据实际需求选择最合适的检测方法。
typeof 运算符及其局限性
typeof 是一个用于检测数据类型的运算符。
typeof value 的返回值首先是一个字符串,其次包含了具体的数据类型标识,例如 "number"、"string"、"boolean"、"undefined"、"object" 和 "function"。
然而,typeof 存在以下局限性:
1) typeof null 的返回结果是 "object"。
2) 无论是数组还是正则表达式,typeof 检测均返回 "object",因此无法通过 typeof 判断一个值是否为数组。
console.log(typeof [12, 23]); // 输出结果为 "Object"
instanceof 与 constructor 检测机制
2、instanceof / constructor
该方法用于检测某个实例是否属于特定的类。
使用 instanceof 或 constructor 可以检测数组和正则表达式。
console.log([] instanceof Array);//->true
console.log(/^$/ instanceof RegExp);//->true
console.log([] instanceof Object);//->true
console.log([].constructor === Array);//->true
console.log([].constructor === Object);//->false
constructor可以避免instanceof检测数组的时候,用Object也是true的问题
console.log({}.constructor === Object);//true<br>console.log([].constructor === Object);//false
局限性:
1) 使用 instanceof 进行检测时,只要当前类位于实例的原型链上(即可以通过原型链 __proto__ 找到它),检测结果均为 true。
var oDiv = document.getElementById("div1");
//HTMLDivElement->HTMLElement->Element->Node->EventTarget->Object
console.log(oDiv instanceof HTMLDivElement);//->true
console.log(oDiv instanceof Node);//->true
console.log(oDiv instanceof Object);//->true
2) 基本数据类型的值不能使用 instanceof 进行检测。
console.log(1 instanceof Number);//->false
数组创建的两种方式(对象、正则、函数等):
对于引用数据类型而言,无论是哪种方式创建出来的都是所属类的实例,且都是对象数据类型的值,两者没有区别。
var ary = [];
var ary = new Array;
对于基本数据类型来说,虽然无论哪种方式创建出来的都是所属类的一个实例(在类的原型上定义的方法都可以使用),但字面量方式创建出来的是基本数据类型,而实例方式创建出来的是对象数据类型。
var num1 = 1;
var num2 = new Number("1");
console.log(typeof num1,typeof num2);//->"number" "object"
3) 在类的原型继承中,instanceof 检测出来的结果其实是不准确的。
function Fn() {}
var f = new Fn;
console.log(f instanceof Array);//->false f不是一个数组,它就是一个普通的实例(普通的对象)
虽然 Fn 继承了 Array,但是 f 没有 length 和数字索引等内容,所以 f 应该不是数组才对,但是用 instanceof 检测的结果却是 true,因为 f 虽然不是数组,但是在 f 的原型链上可以找到 Array。
function Fn() {
}
Fn.prototype = new Array;//->Fn子类继承了Array这个父类中的属性和方法
var f = new Fn;
console.log(f instanceof Array);//->true
Object.prototype.toString 检测方法
3、Object.prototype.toString.call(value) -> 找到 Object 原型上的 toString 方法,让方法执行,并且让方法中的 this 变为 value(value 就是我们要检测数据类型的值)。
Object.prototype.toString 常用来判断对象值属于哪种内置属性,它返回一个 JSON 字符串——"[object 数据类型]"。
由于许多引用类型都重写了 Object 继承来的 toString 方法,所以我们通常使用 call 或者 apply 借用 Object.prototype.toString 函数来判断数据类型。
当然,这样调用的默认前提是 Object.prototype.toString 没有被重写。
toString:一个方法,转换为字符串数据类型用的方法。
每一个数据类型所属类的原型上都有 toString 方法,例如:Number.prototype、String.prototype、Array.prototype、Function.prototype 等。
除了 Object 上的 toString,其他类原型上的 toString 都是把当前的数据值转换为字符串的意思。
null 和 undefined 比较特殊:它们所属类 Null/Undefined 的原型上也有 toString,只不过不让我们用而已,不仅如此其实类的原型都给屏蔽了。
HTML 元素对象的 toString:虽然它的原型链很长,但是在其它类的原型上都没有 toString,只有在最底层 Object.prototype 上才有。
var oDiv = document.getElementById("div1");
oDiv.toString(); //->调用的其实也是Object.prototype.toString...
//alert、document.write 这两种输出的方式其实都是把要输出的内容先转换为字符串,然后再输出的<br>
alert([]); //->""
alert(true); //->"true"
alert({}); //->这个就要调用Object.prototype上的toString了 ->"[object Object]"
//定义toString变量是为了简便书写,同时降低作用域链检索的性能损耗
var toString = Object.prototype.toString;
console.log(toString.call(1));//[object Number]
console.log(toString.call(undefined));//[object Undefined]
console.log(toString.call(null));//[object Null]
console.log(toString.call(false));//[object Boolean]
console.log(toString.call("s"));//[object String]
console.log(toString.call({}));//[object Object]
console.log(toString.call(/[a]/g));//[object RegExp]
console.log(toString.call(function(){}));//[object Function]
is 系列检测函数的实现
is 系列函数的简易实现
在明白数据类型怎么检测后,下面我们来简单实现 is 系列检测函数。
var dataType = {
'[object Null]' : 'null',
'[object Undefined]' : 'undefiend',
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]' : 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regexp',
'[object Object]' : 'object',
'[object Error]' : 'error'
},
toString = Object.prototype.toString;
function type(obj) {
return dataType[toString.call(obj)];
}
//生成is系列函数
function createValidType() {
for(var p in dataType) {
var objType = p.slice(8, -1);
(function(objType) {
window['is' + objType] = function(obj) {
return type(obj) === objType.toLowerCase();
}
})(objType)
}
}
createValidType();
console.log(isObject({}));//true
console.log(isDate(new Date()));//true
console.log(isBoolean(false));//true
console.log(isString(1));//false
console.log(isError(1));//false
console.log(isError(new Error()));//true
console.log(isArray([]));//true
console.log(isArray(1));//false
上面代码里分别实现了 isNull、isUndefined、isBoolean、isNumber、isString、isFunction、isArray、isDate、isRegExp、isObject、isError 这 11 个检测函数。同时也实现了 type 函数,用以检测数据类型。
console.log(type({}));//"object"
console.log(type(new Date()));//"date"
console.log(type(false));//"boolean"
console.log(type(1));//"number"
console.log(type(1));//"number"
console.log(type(new Error()));//"error"
console.log(type([]));//"array"
console.log(type(1));//"number"
createValidType 函数巧用闭包保存数据状态的特性,批量生成 is 系列函数。
以上所述是小编给大家介绍的 JS 中检测数据类型的几种方式及优缺点小结,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对本站网站的支持!