JavaScript
类型判断
一、typeof
最常用,但有坑。
typeof 'hello' // 'string'
typeof 123 // 'number'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof Symbol() // 'symbol'
typeof BigInt(1) // 'bigint'
typeof function () {} // 'function'
// 坑:
typeof null // 'object' ← 历史 bug,永远不会修
typeof [] // 'object' ← 分不清数组和对象
typeof {} // 'object'结论:能判断基本类型(除 null),不能细分引用类型。
二、instanceof
原型链判断
原理:沿着对象的 __proto__ 链往上找,看能否找到构造函数的 prototype。
[] instanceof Array // true
[] instanceof Object // true(原型链最终到 Object.prototype)
// 原型链过程:
// [].__proto__ === Array.prototype ✓ → true
// [].__proto__.__proto__ === Object.prototype ✓ → 也是 true手写 instanceof:
function myInstanceof(obj, Constructor) {
let proto = Object.getPrototypeOf(obj)
while (proto !== null) {
if (proto === Constructor.prototype) return true
proto = Object.getPrototypeOf(proto)
}
return false
}
myInstanceof([], Array) // true
myInstanceof([], Object) // true缺点:
// 1. 不能判断基本类型
'hello' instanceof String // false(基本类型不是对象)
// 2. 跨 iframe 失效
// iframe 里的数组和主页面的 Array 不是同一个构造函数三、Object.prototype.toString.call()
最准确
原理:每个对象内部有 [[Class]] 标签,toString 会读取它。
Object.prototype.toString.call('hello') // '[object String]'
Object.prototype.toString.call(123) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(null) // '[object Null]' ← 能正确识别 null
Object.prototype.toString.call([]) // '[object Array]' ← 能区分数组
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call(function () {}) // '[object Function]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(/abc/) // '[object RegExp]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new Set()) // '[object Set]'封装工具函数:
function getType(val) {
return Object.prototype.toString.call(val).slice(8, -1).toLowerCase()
}
getType(null) // 'null'
getType([]) // 'array'
getType(new Map()) // 'map'为什么要用 call? 数组、Date 等重写了自己的 toString,直接调用拿不到 [[Class]],必须借用 Object.prototype 上的那个。
四、Array.isArray()
专门判断数组,跨 iframe 也准。
Array.isArray([]) // true
Array.isArray({}) // false
Array.isArray('hello') // false内部等价于 Object.prototype.toString.call(arg) === '[object Array]'。
五、constructor
(123).constructor === Number // true
'hello'.constructor === String // true
[].constructor === Array // true
// 缺点:
null.constructor // 报错
undefined.constructor // 报错
// 原型链被改写后也不准六、对比总结
| 方法 | 基本类型 | 引用类型细分 | null | 跨 iframe |
|---|---|---|---|---|
typeof | ✅(除 null) | ❌ | ❌ 返回 'object' | ✅ |
instanceof | ❌ | ✅ | ❌ | ❌ |
toString.call() | ✅ | ✅ | ✅ | ✅ |
Array.isArray | — | 仅数组 | — | ✅ |
constructor | ✅ | ✅ | ❌ 报错 | ❌ |
判断基本类型用
typeof,判断引用类型用instanceof(原型链查找),最准确的是Object.prototype.toString.call(),判断数组专用Array.isArray()。