您现在的位置是:网站首页 > 类型检测(typeof, instanceof)文章详情
类型检测(typeof, instanceof)
陈川
【
JavaScript
】
47999人已围观
5178字
JavaScript作为动态类型语言,变量类型在运行时才能确定。类型检测是开发中常见的需求,主要使用typeof和instanceof操作符。
typeof操作符
typeof返回一个字符串,表示未经计算的操作数的类型。基本用法:
javascript
console.log(typeof 42); // "number"
console.log(typeof 'blubber'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undeclaredVariable); // "undefined"
console.log(typeof {a: 1}); // "object"
console.log(typeof [1, 2, 4]); // "object"
console.log(typeof new Date()); // "object"
console.log(typeof function() {}); // "function"
console.log(typeof null); // "object" (历史遗留问题)
typeof的特殊情况:
- 对null返回"object"是JavaScript早期实现的bug,一直保留至今
- 函数返回"function",尽管函数本质也是对象
- 数组返回"object",无法区分数组和普通对象
instanceof操作符
instanceof用于检测构造函数的prototype属性是否出现在对象的原型链中。基本语法:
javascript
object instanceof constructor
示例:
javascript
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car); // true
console.log(auto instanceof Object); // true
const simpleStr = "This is a simple string";
console.log(simpleStr instanceof String); // false (字面量不是对象)
const strObj = new String("String created with constructor");
console.log(strObj instanceof String); // true
instanceof的工作原理:
- 获取对象的原型:Object.getPrototypeOf(obj)
- 获取构造函数的prototype属性
- 比较两者是否相等,如果不相等则继续沿着原型链向上查找
- 如果找到则返回true,否则返回false
类型检测的实际应用
区分数组和对象
javascript
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
// 或者使用 Array.isArray(obj)
}
console.log(isArray([])); // true
console.log(isArray({})); // false
检测NaN
javascript
function isNaN(value) {
// NaN是JavaScript中唯一不等于自身的值
return value !== value;
}
console.log(isNaN(NaN)); // true
console.log(isNaN(42)); // false
安全类型检测函数
javascript
function getType(obj) {
if (obj === null) return 'null';
if (obj === undefined) return 'undefined';
const type = typeof obj;
if (type !== 'object') return type;
// 获取对象的[[Class]]内部属性
const toString = Object.prototype.toString;
const typeString = toString.call(obj);
// 匹配类似[object Type]的字符串
const match = typeString.match(/\[object (\w+)\]/);
if (!match) return 'object';
const classType = match[1].toLowerCase();
// 特殊处理一些类型
if (classType === 'number' && isNaN(obj)) return 'nan';
if (classType === 'boolean' || classType === 'string') return classType;
return classType;
}
console.log(getType([])); // "array"
console.log(getType(new Date())); // "date"
console.log(getType(/test/)); // "regexp"
console.log(getType(NaN)); // "nan"
原型链与instanceof
理解instanceof需要深入理解JavaScript的原型链机制:
javascript
function Parent() {}
function Child() {}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child = new Child();
console.log(child instanceof Child); // true
console.log(child instanceof Parent); // true
console.log(child instanceof Object); // true
// 修改原型链会影响instanceof的结果
Child.prototype = {};
console.log(child instanceof Child); // false
Symbol.hasInstance
ES6引入了Symbol.hasInstance,允许自定义instanceof的行为:
javascript
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false
类型检测的边界情况
跨窗口/iframe问题
在不同iframe中创建的数组,instanceof Array会返回false:
html
<iframe id="iframe"></iframe>
<script>
const iframe = document.getElementById('iframe');
const iframeArray = iframe.contentWindow.Array;
const arr = new iframeArray(1, 2, 3);
console.log(arr instanceof Array); // false
console.log(Array.isArray(arr)); // true
</script>
原始值包装对象
javascript
const str = "hello";
console.log(str instanceof String); // false
const strObj = new String("hello");
console.log(strObj instanceof String); // true
现代JavaScript的类型检测
ES6+引入了更多类型检测方法:
javascript
// 检查数组
console.log(Array.isArray([])); // true
// 检查NaN
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("NaN")); // false
// 检查有限数字
console.log(Number.isFinite(Infinity)); // false
// 检查整数
console.log(Number.isInteger(3)); // true
console.log(Number.isInteger(3.1)); // false
// 安全整数检查
console.log(Number.isSafeInteger(Math.pow(2, 53))); // false
类型检测的性能考虑
不同类型检测方法的性能差异:
javascript
const obj = {};
const arr = [];
const iterations = 1000000;
console.time('typeof');
for (let i = 0; i < iterations; i++) {
typeof obj;
}
console.timeEnd('typeof');
console.time('instanceof');
for (let i = 0; i < iterations; i++) {
arr instanceof Array;
}
console.timeEnd('instanceof');
console.time('Array.isArray');
for (let i = 0; i < iterations; i++) {
Array.isArray(arr);
}
console.timeEnd('Array.isArray');
console.time('Object.prototype.toString');
for (let i = 0; i < iterations; i++) {
Object.prototype.toString.call(arr) === '[object Array]';
}
console.timeEnd('Object.prototype.toString');
类型检测的最佳实践
- 基本类型检测优先使用typeof
- 数组检测使用Array.isArray()
- 自定义对象类型检测使用instanceof
- 需要精确类型信息时使用Object.prototype.toString.call()
- 注意null和undefined的特殊处理
- 跨环境类型检测要考虑iframe和不同全局上下文的情况