在 JavaScript 中,类型判断是一个常见的需求。以下是几种常用的类型判断方法及其适用场景:
typeof 操作符
typeof 操作符可以用来判断大多数原始类型和函数类型,但对于 null 和数组等复杂类型的判断有些不足。
console.log(typeof 42); // "number"
console.log(typeof 'hello'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol()); // "symbol"
console.log(typeof BigInt(10)); // "bigint"
console.log(typeof function(){}); // "function"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof new Date()); // "object"
console.log(typeof null); // "object" (这是一个历史遗留问题)
instanceof 操作符
instanceof 操作符用于判断一个对象是否是某个构造函数的实例。它通过检查对象的原型链来进行判断。
// 原型链检查
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(function(){} instanceof Function); // true
// 在自定义类和继承关系中,`instanceof` 可以正确反映继承关系。
function Animal() {}
function Dog() {}
Dog.prototype = new Animal();
var dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
// 假设在 iframe 中执行
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = new iframe.contentWindow.Array();
console.log(iframeArray instanceof Array); // false
console.log(iframeArray instanceof iframe.contentWindow.Array); // true
// 可以通过重写 `Symbol.hasInstance` 方法来自定义 `instanceof` 的行为。
class MyClass {
static [Symbol.hasInstance](instance) {
return instance.customProperty === true;
}
}
const obj = { customProperty: true };
console.log(obj instanceof MyClass); // true
总结
instanceof通过检查对象的原型链来确定关系。- 手动修改原型链会影响
instanceof的结果。 - 在不同的 iframe 或窗口之间使用
instanceof可能会失效。 instanceof适用于检测对象的实例关系,而typeof适用于检测基本类型。- 可以通过重写
Symbol.hasInstance方法来自定义instanceof的行为。
Object.prototype.toString.call()
这是一个强大的方法,可以准确判断各种类型。它返回一个表示对象类型的字符串。
console.log(Object.prototype.toString.call(123)); // "[object Number]"
console.log(Object.prototype.toString.call('hello')); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call({})); // "[object Object]"
console.log(Object.prototype.toString.call(new Date())); // "[object Date]"
console.log(Object.prototype.toString.call(function(){})); // "[object Function]"
此方法为什么能检测数据类型呢?起初我也很奇怪,只是记住了此方法,并未深究,今天让我们来一探究竟。
在介绍Object.prototype.toString方法之前,我们先把toString()方法和Object.prototype.toString.call()方法进行对比。
var arr=[1,2];
//直接对一个数组调用toString()
arr.toString();// "1,2"
//通过call指定arr数组为Object.prototype对象中的toString方法的上下文
Object.prototype.toString.call(arr); //"[object Array]"
数组对象上面的toString()调用到的实际是重写后的方法,并不是Object.prototype中的toString(),但是Object.prototype中的toString()也是被继承下来了。
当在Object.prototype(原型链上)调用 toString 方法时,执行以下步骤:
- 如果this 值是undefined,则返回
[object Undefined]。 - 如果this 值是null,则返回
[object Null]。 - 让 O 是通过使用 this 值作为参数调用 ToObject 所得到的结果。
- 让 class 是 O 的内部属性 [[Class]] 的值。
- 返回连接三个字符串
"[object",class和"]"后的字符串值。
ToObject用于将非对象类型的值转换为对象。以下是如何将其描述为一个步骤:
- 如果
this值是undefined或null,抛出TypeError异常。 - 否则,将
this值转换为对象并返回。
.call()的作用是重写this指针的指向,通过call()指定arr数组为Object.prototype对象中的toString方法的上下文,this指向的是arr,如果不加.call()的话,this指向为Object,Object的数据类型自然是Object。
Array.isArray()
Array.isArray 方法专门用于判断一个值是否为数组。
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false
console.log(Array.isArray('hello')); // false
. 自定义类型判断函数
有时你可能需要自定义类型判断函数,结合以上方法来实现更复杂的类型判断逻辑。
function getType(value) {
if (value === null) return 'null';
if (typeof value === 'undefined') return 'undefined';
if (typeof value === 'object') {
if (Array.isArray(value)) return 'array';
if (value instanceof Date) return 'date';
if (value instanceof RegExp) return 'regexp';
return 'object';
}
return typeof value;
}
console.log(getType(123)); // "number"
console.log(getType('hello')); // "string"
console.log(getType(true)); // "boolean"
console.log(getType(undefined)); // "undefined"
console.log(getType(null)); // "null"
console.log(getType([])); // "array"
console.log(getType({})); // "object"
console.log(getType(new Date())); // "date"
console.log(getType(/abc/)); // "regexp"
console.log(getType(function(){})); // "function"
总结
typeof适用于大多数原始类型和函数类型的判断。instanceof适用于判断对象是否是某个构造函数的实例。Object.prototype.toString.call()是一种通用且强大的类型判断方法。Array.isArray()专门用于判断数组类型。- 自定义类型判断函数可以结合多种方法实现更复杂的类型判断逻辑。