一、JavaScript 数据类型
1.1 原始类型 (Primitive Types)
- Undefined:
undefined - Null:
null - Boolean:
true,false - Number:
42,3.14,NaN,Infinity - String:
"hello",'world' - Symbol:
Symbol(),Symbol('desc')(ES6) - BigInt:
9007199254740991n(ES2020)
1.2 引用类型 (Reference Types)
- Object:
{},new Object() - Array:
[],new Array() - Function:
function() {},() => {} - Date:
new Date() - RegExp:
/regex/,new RegExp() - Map:
new Map()(ES6) - Set:
new Set()(ES6) - WeakMap:
new WeakMap()(ES6) - WeakSet:
new WeakSet()(ES6) - Promise:
new Promise()(ES6) - 其他内置对象:
Error,Math,JSON等
二、类型检测方法
2.1 typeof 操作符
// 基本类型检测
typeof undefined // "undefined"
typeof true // "boolean"
typeof 42 // "number"
typeof "hello" // "string"
typeof Symbol() // "symbol"
typeof 9007199254740991n // "bigint"
// 函数检测
typeof function() {} // "function"
typeof class MyClass {} // "function"
// 局限性
typeof null // "object" (历史遗留bug)
typeof [] // "object"
typeof {} // "object"
typeof new Date() // "object"
typeof /regex/ // "object"
2.2 instanceof 操作符
// 检测构造函数
[] instanceof Array // true
{} instanceof Object // true
new Date() instanceof Date // true
// 原型链检测
[] instanceof Object // true (所有对象都是Object的实例)
function() {} instanceof Function // true
// 局限性
'hello' instanceof String // false (原始类型)
42 instanceof Number // false (原始类型)
2.3 Object.prototype.toString.call()
// 最全面的类型检测方法
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(42) // "[object Number]"
Object.prototype.toString.call("hello") // "[object String]"
Object.prototype.toString.call(Symbol()) // "[object Symbol]"
Object.prototype.toString.call(9007199254740991n) // "[object BigInt]"
// 对象类型检测
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.call(function() {}) // "[object Function]"
Object.prototype.toString.call(new Date()) // "[object Date]"
Object.prototype.toString.call(/regex/) // "[object RegExp]"
Object.prototype.toString.call(new Map()) // "[object Map]"
Object.prototype.toString.call(new Set()) // "[object Set]"
Object.prototype.toString.call(new Promise(() => {})) // "[object Promise]"
2.4 专用检测方法
// 数组检测
Array.isArray([]) // true
Array.isArray({}) // false
// NaN 检测
Number.isNaN(NaN) // true
Number.isNaN("hello") // false (不会强制类型转换)
isNaN("hello") // true (会强制类型转换)
// 有限数字检测
Number.isFinite(42) // true
Number.isFinite(Infinity) // false
Number.isFinite("42") // false
// 整数检测
Number.isInteger(42) // true
Number.isInteger(42.0) // true
Number.isInteger(42.1) // false
// BigInt 检测
typeof 42n === 'bigint' // true
// Symbol 检测
typeof Symbol() === 'symbol' // true
三、综合类型检测函数
3.1 通用类型检测函数
function getType(value) {
// 处理 null 和 undefined
if (value === null) return 'null';
if (value === undefined) return 'undefined';
const type = typeof value;
// 处理基本类型
if (type !== 'object' && type !== 'function') {
return type;
}
// 使用 Object.prototype.toString 获取详细类型
const toString = Object.prototype.toString.call(value);
const match = toString.match(/\[object (\w+)\]/);
if (match) {
return match[1].toLowerCase();
}
return 'object';
}
// 测试用例
console.log(getType(null)); // "null"
console.log(getType(undefined)); // "undefined"
console.log(getType(42)); // "number"
console.log(getType("hello")); // "string"
console.log(getType(true)); // "boolean"
console.log(getType(Symbol())); // "symbol"
console.log(getType(42n)); // "bigint"
console.log(getType([])); // "array"
console.log(getType({})); // "object"
console.log(getType(function() {})); // "function"
console.log(getType(new Date())); // "date"
console.log(getType(/regex/)); // "regexp"
console.log(getType(new Map())); // "map"
console.log(getType(new Set())); // "set"
3.2 增强版类型检测(支持自定义类型)
class TypeDetector {
static getType(value) {
if (value === null) return 'null';
if (value === undefined) return 'undefined';
const type = typeof value;
if (type !== 'object' && type !== 'function') {
return type;
}
return Object.prototype.toString.call(value)
.slice(8, -1)
.toLowerCase();
}
static isPrimitive(value) {
return value === null ||
typeof value !== 'object' && typeof value !== 'function';
}
static isObject(value) {
return value !== null && typeof value === 'object';
}
static isFunction(value) {
return typeof value === 'function';
}
static isArray(value) {
return Array.isArray(value);
}
static isPlainObject(value) {
return Object.prototype.toString.call(value) === '[object Object]' &&
Object.getPrototypeOf(value) === Object.prototype;
}
static isEmpty(value) {
if (value === null || value === undefined) return true;
if (Array.isArray(value) || typeof value === 'string') return value.length === 0;
if (this.isPlainObject(value)) return Object.keys(value).length === 0;
if (value instanceof Map || value instanceof Set) return value.size === 0;
return false;
}
}
// 使用示例
TypeDetector.getType([]) // "array"
TypeDetector.isPrimitive("hello") // true
TypeDetector.isObject({}) // true
TypeDetector.isPlainObject({}) // true
TypeDetector.isPlainObject(new Date()) // false
TypeDetector.isEmpty([]) // true
TypeDetector.isEmpty({}) // true
四、特殊值检测
4.1 Null 和 Undefined 检测
// 严格相等(推荐)
value === null
value === undefined
// 宽松相等
value == null // 同时检测 null 和 undefined
// typeof 检测
typeof value === 'undefined'
4.2 NaN 检测
// 可靠的方法
Number.isNaN(value)
// 利用 NaN 的特性(自身不相等)
value !== value
// 不推荐的方法(会进行类型转换)
isNaN(value)
4.3 假值检测
// JavaScript 的假值
false, 0, "", null, undefined, NaN
// 检测假值
!!value === false
Boolean(value) === false
// 安全检测(排除 null 和 undefined)
value ? true : false
五、ES6+ 新增类型检测
5.1 Map 和 Set 检测
// Map 检测
value instanceof Map
Object.prototype.toString.call(value) === '[object Map]'
// Set 检测
value instanceof Set
Object.prototype.toString.call(value) === '[object Set]'
// WeakMap 和 WeakSet 检测
value instanceof WeakMap
value instanceof WeakSet
5.2 Promise 检测
// Promise 检测
value instanceof Promise
Object.prototype.toString.call(value) === '[object Promise]'
typeof value.then === 'function' // thenable 检测
5.3 迭代器检测
// 可迭代对象检测
typeof value[Symbol.iterator] === 'function'
// 生成器函数检测
Object.prototype.toString.call(value) === '[object GeneratorFunction]'
六、面试重点与常见问题
6.1 面试常见问题
-
typeof null为什么返回 "object"?- 历史遗留问题,JavaScript 初版用类型标签区分值类型
- null 的机器码是全0,对象类型标签也是0
-
如何准确判断数组类型?
Array.isArray()(ES5+)Object.prototype.toString.call()- 避免使用
instanceof(跨iframe有问题)
-
instanceof的原理是什么?- 检查构造函数的
prototype是否在对象的原型链上
- 检查构造函数的
-
如何判断一个对象是普通对象?
Object.getPrototypeOf(obj) === Object.prototypeobj.constructor === Object
6.2 最佳实践总结
// 类型检测最佳实践
const typeCheck = {
// 基本类型
isUndefined: val => val === undefined,
isNull: val => val === null,
isBoolean: val => typeof val === 'boolean',
isNumber: val => typeof val === 'number',
isString: val => typeof val === 'string',
isSymbol: val => typeof val === 'symbol',
isBigInt: val => typeof val === 'bigint',
// 引用类型
isObject: val => val !== null && typeof val === 'object',
isArray: val => Array.isArray(val),
isFunction: val => typeof val === 'function',
isDate: val => val instanceof Date,
isRegExp: val => val instanceof RegExp,
isMap: val => val instanceof Map,
isSet: val => val instanceof Set,
isPromise: val => val instanceof Promise,
// 特殊值
isNaN: val => Number.isNaN(val),
isFinite: val => Number.isFinite(val),
isInteger: val => Number.isInteger(val),
// 通用方法
getType: val => {
if (val === null) return 'null';
const type = typeof val;
if (type !== 'object') return type;
return Object.prototype.toString.call(val).slice(8, -1).toLowerCase();
}
};
七、实际应用场景
7.1 参数验证
function validateConfig(config) {
if (!typeCheck.isPlainObject(config)) {
throw new Error('Config must be a plain object');
}
if (config.timeout && !typeCheck.isNumber(config.timeout)) {
throw new Error('Timeout must be a number');
}
if (config.retry && !typeCheck.isBoolean(config.retry)) {
throw new Error('Retry must be a boolean');
}
}
7.2 深拷贝实现中的类型检测
function deepClone(value) {
// 基本类型直接返回
if (!typeCheck.isObject(value)) {
return value;
}
// 处理数组
if (typeCheck.isArray(value)) {
return value.map(item => deepClone(item));
}
// 处理日期
if (typeCheck.isDate(value)) {
return new Date(value.getTime());
}
// 处理正则
if (typeCheck.isRegExp(value)) {
return new RegExp(value);
}
// 处理普通对象
const cloned = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
cloned[key] = deepClone(value[key]);
}
}
return cloned;
}