目录
一、基础检测方法
1. typeof 操作符
2. instanceof 运算符
3. Object.prototype.toString.call()
二、进阶检测技巧
1. 特定类型检测方法
2. 构造函数属性检测
3. ES6 Symbol.toStringTag 自定义类型
三、特殊类型检测场景
1. null 与 undefined 检测
2. 纯对象检测(排除数组等)
3. 跨窗口对象检测
四、现代框架的检测方案
1. Lodash类型检测方法
2. Vue源码中的检测逻辑
五、类型检测方案对比
六、最佳实践建议
从基础到进阶,全面解析类型检测的8种方案
JavaScript作为动态类型语言,类型检测是开发中最重要的基础技能之一。本文将系统梳理从基础到高级的所有类型检测方法,通过代码示例对比不同方案的适用场景,并揭示现代框架的类型检测底层原理。
一、基础检测方法
1. typeof
操作符
原理:返回值的类型标签(底层二进制判断)
特点:
-
对原始类型有效,但对
null
和对象类型判断不准
typeof 'str' // 'string'
typeof 42 // 'number'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof Symbol() // 'symbol'
typeof null // 'object' (历史遗留问题)
typeof [] // 'object'
typeof {} // 'object'
typeof function(){} // 'function'
2. instanceof
运算符
原理:检测构造函数的prototype
是否在对象的原型链上
适用场景:检测自定义对象类型
[] instanceof Array // true
new Date() instanceof Date // true
function Person() {}
const p = new Person();
p instanceof Person // true
// 局限性:跨窗口对象检测失效
iframe.contentWindow.Array !== window.Array
iframeArray instanceof Array // false
3. Object.prototype.toString.call()
原理:调用对象内部的[[Class]]
属性(ES5规范)
返回值:[object Type]
格式字符串
Object.prototype.toString.call('') // [object String]
Object.prototype.toString.call(42) // [object Number]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call({}) // [object Object]
// 封装通用检测函数
function getType(obj) {
return Object.prototype.toString.call(obj)
.slice(8, -1)
.toLowerCase();
}
二、进阶检测技巧
1. 特定类型检测方法
-
数组检测:
Array.isArray([]) // true(ES5+最佳方案) // Polyfill写法: if (!Array.isArray) { Array.isArray = arg => Object.prototype.toString.call(arg) === '[object Array]'; }
-
NaN检测:
Number.isNaN(NaN) // true(ES6+) // 兼容方案: function isNaN(val) { return val !== val; }
2. 构造函数属性检测
[].constructor === Array // true
{}.constructor === Object // true
// 风险:constructor属性可被修改
function Test() {}
const obj = new Test();
obj.constructor = Object;
obj.constructor === Object // true
3. ES6 Symbol.toStringTag
自定义类型
允许对象自定义toString
标签:
const myObj = {
[Symbol.toStringTag]: 'MyCustomType'
};
Object.prototype.toString.call(myObj) // [object MyCustomType]
// 内置对象的应用:
Object.prototype.toString.call(new Promise(() => {})) // [object Promise]
三、特殊类型检测场景
1. null
与 undefined
检测
// 安全检测undefined(避免未声明报错)
typeof variable === 'undefined'
// 检测null
variable === null
// 同时检测null和undefined
variable == null
2. 纯对象检测(排除数组等)
function isPlainObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]' &&
Object.getPrototypeOf(obj) === Object.prototype;
}
isPlainObject({}) // true
isPlainObject([]) // false
isPlainObject(null) // false
3. 跨窗口对象检测
// 安全检测数组(跨iframe场景)
function isArray(value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
四、现代框架的检测方案
1. Lodash类型检测方法
_.isObject({}) // true
_.isPlainObject({}) // true(纯对象)
_.isElement(document.body) // true(DOM元素)
_.isMap(new Map()) // true
2. Vue源码中的检测逻辑
// vue-next源码节选
export const isArray = Array.isArray
export const isMap = (val: unknown): val is Map<any, any> =>
toTypeString(val) === '[object Map]'
export const isSet = (val: unknown): val is Set<any> =>
toTypeString(val) === '[object Set]'
五、类型检测方案对比
检测方式 | 优点 | 缺点 | 推荐使用场景 |
---|---|---|---|
typeof | 快速检测原始类型 | 无法区分对象类型 | 检测undefined 、函数 |
instanceof | 适合自定义类型 | 跨窗口失效、不适用于原始类型 | 检测已知构造函数对象 |
Object.prototype.toString | 最全面准确的方案 | 代码较长 | 需要精确类型判断 |
专用检测方法 | 语义明确 | 需要记忆多个API | 数组、NaN等特定类型 |
六、最佳实践建议
-
基础场景:
-
优先使用
typeof
检测原始类型(除null
) -
使用
Array.isArray()
检测数组
-
-
精确判断:
-
使用
Object.prototype.toString.call()
获取精确类型
-
-
框架开发:
-
结合
Symbol.toStringTag
自定义对象类型标签 -
使用
Map
/Set
等内置类型的专用检测方法
-
-
安全检测:
-
使用
variable == null
同时检测null
和undefined
-
避免直接访问未声明变量的属性
-