在JavaScript开发中,准确判断变量类型是编写健壮代码的基础。由于JavaScript是动态类型语言,变量类型在运行时可能发生变化,因此掌握多种类型判断方法及其适用场景至关重要。本文将系统介绍JavaScript中判断变量类型的多种方法,并通过实际应用场景解析它们的优缺点和最佳实践。
一、typeof操作符
1.1 基本用法
typeof 是JavaScript中最基础的类型判断操作符,它返回一个表示变量类型的字符串。
// 基本类型判断
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (历史遗留问题)
console.log(typeof Symbol()); // "symbol"
console.log(typeof 42n); // "bigint"
// 引用类型判断
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"
console.log(typeof new Date()); // "object"
console.log(typeof /regex/); // "object"
1.2 局限性
typeof 的主要局限性在于:
- 无法区分具体对象类型(所有对象都返回”object”)
null被错误地判断为 “object”- 无法检测自定义类的实例
// 无法区分对象类型
console.log(typeof []); // "object"
console.log(typeof {}); // "object"
console.log(typeof null); // "object" (错误)
// 无法检测自定义类
class MyClass {}
const instance = new MyClass();
console.log(typeof instance); // "object"
1.3 实际应用场景
typeof 适合用于:
- 快速检查基本类型:特别是检查变量是否为
undefined - 函数检测:判断变量是否为函数
- 性能敏感场景:
typeof是原生操作符,执行效率高
// 场景1:检查参数是否为函数
function debounce(fn, delay) {
if (typeof fn !== 'function') {
throw new Error('debounce expects a function as first argument');
}
// ... 实现防抖逻辑
}
// 场景2:检查变量是否已定义
if (typeof myVar === 'undefined') {
console.log('变量未定义');
}
// 场景3:处理可选参数
function greet(name) {
if (typeof name === 'undefined') {
name = 'Guest';
}
return `Hello, ${name}!`;
}
二、instanceof操作符
2.1 基本用法
instanceof 用于判断对象是否是某个构造函数的实例,它检查原型链。
// 内置对象判断
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(new Date() instanceof Date); // true
console.log(/regex/ instanceof RegExp); // true
// 自定义类判断
class Person {
constructor(name) {
this.name = name;
}
}
const alice = new Person('Alice');
console.log(alice instanceof Person); // true
console.log(alice instanceof Object); // true (因为Person继承自Object)
// 继承关系判断
class Student extends Person {}
const bob = new Student('Bob');
console.log(bob instanceof Student); // true
console.log(bob instanceof Person); // true
console.log(bob instanceof Object); // true
2.2 局限性
instanceof 的主要问题:
- 无法判断基本类型
- 在跨框架(iframe)场景下可能失效
- 无法判断
null和undefined
// 无法判断基本类型
console.log(42 instanceof Number); // false
console.log("hello" instanceof String); // false
console.log(true instanceof Boolean); // false
// 跨iframe问题
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = iframe.contentWindow.Array;
const arr = new iframeArray();
console.log(arr instanceof Array); // false (跨iframe)
console.log(arr instanceof iframe.contentWindow.Array); // true
2.3 实际应用场景
instanceof 适合用于:
- 自定义类实例判断:判断对象是否为特定类的实例
- 原型链检查:检查继承关系
- 框架内对象判断:在单一框架内判断内置对象类型
// 场景1:处理不同类型的事件对象
function handleEvent(event) {
if (event instanceof MouseEvent) {
// 处理鼠标事件
console.log('Mouse event:', event.clientX, event.clientY);
} else if (event instanceof KeyboardEvent) {
// 处理键盘事件
console.log('Keyboard event:', event.key);
} else {
// 处理其他事件
console.log('Other event');
}
}
// 场景2:验证输入参数类型
function processData(data) {
if (!(data instanceof Array)) {
throw new Error('Expected an array');
}
// 处理数组数据
return data.map(item => item * 2);
}
// 场景3:实现类型守卫(Type Guard)
function isPerson(obj) {
return obj instanceof Person;
}
function processPerson(obj) {
if (isPerson(obj)) {
// TypeScript会在这里推断obj为Person类型
console.log(obj.name);
}
}
三、Object.prototype.toString.call()
3.1 基本用法
这是最准确的类型判断方法,它返回一个格式为 [object Type] 的字符串。
// 基本类型判断
console.log(Object.prototype.toString.call(42)); // "[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(null)); // "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
// 引用类型判断
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call({})); // "[object Object]"
console.log(Object.prototype.toString.call(function(){})); // "[object Function]"
console.log(Object.prototype.toString.call(new Date())); // "[object Date]"
console.log(Object.prototype.toString.call(/regex/)); // "[object RegExp]"
console.log(Object.prototype.toString.call(new Set())); // "[object Set]"
console.log(Object.prototype.toString.call(new Map())); // "[object Map]"
3.2 封装成工具函数
为了方便使用,通常会将其封装成工具函数:
// 封装成类型判断工具
const Type = {
// 基本类型判断
isNumber: (value) => Object.prototype.toString.call(value) === '[object Number]',
isString: (value) => Object.prototype.toString.call(value) === '[object String]',
isBoolean: (value) => Object.prototype.toString.call(value) === '[object Boolean]',
isNull: (value) => Object.prototype.toString.call(value) === '[object Null]',
isUndefined: (value) => Object.prototype.toString.call(value) === '[object Undefined]',
isSymbol: (value) => Object.prototype.toString.call(value) === '[object Symbol]',
isBigInt: (value) => Object.prototype.toString.call(value) === '[object BigInt]',
// 引用类型判断
isArray: (value) => Object.prototype.toString.call(value) === '[object Array]',
isObject: (value) => Object.prototype.toString.call(value) === '[object Object]',
isFunction: (value) => Object.prototype.toString.call(value) === '[object Function]',
isDate: (value) => Object.prototype.toString.call(value) === '[object Date]',
isRegExp: (value) => Object.prototype.toString.call(value) === '[object RegExp]',
isSet: (value) => Object.prototype.toString.call(value) === '[object Set]',
isMap: (value) => Object.prototype.toString.call(value) === '[object Map]',
isWeakMap: (value) => Object.prototype.toString.call(value) === '[object WeakMap]',
isWeakSet: (value) => Object.prototype.toString.call(value) === '[object WeakSet]',
isPromise: (value) => Object.prototype.toString.call(value) === '[object Promise]',
// 特殊判断
isNaN: (value) => Object.prototype.toString.call(value) === '[object Number]' && Number.isNaN(value),
isFinite: (value) => Object.prototype.toString.call(value) === '[object Number]' && Number.isFinite(value),
// 通用类型判断
getType: (value) => {
const str = Object.prototype.toString.call(value);
return str.slice(8, -1).toLowerCase();
}
};
// 使用示例
console.log(Type.isArray([1, 2, 3])); // true
console.log(Type.isObject({})); // true
console.log(Type.isDate(new Date())); // true
console.log(Type.getType([])); // "array"
console.log(Type.getType({})); // "object"
3.3 实际应用场景
Object.prototype.toString.call() 适合用于:
- 精确类型判断:需要区分具体对象类型时
- 类型守卫:在TypeScript中作为类型守卫
- 数据验证:验证API返回的数据结构
// 场景1:API数据验证
function validateApiResponse(response) {
if (!Type.isObject(response)) {
throw new Error('Response must be an object');
}
if (!Type.isArray(response.data)) {
throw new Error('Response data must be an array');
}
if (!Type.isString(response.status)) {
throw new Error('Response status must be a string');
}
return true;
}
// 场景2:处理异步操作结果
async function fetchData() {
const result = await someAsyncOperation();
if (Type.isPromise(result)) {
// 如果返回的是Promise,继续等待
return await result;
} else if (Type.isArray(result)) {
// 如果返回的是数组,直接处理
return result.map(item => processItem(item));
} else if (Type.isObject(result)) {
// 如果返回的是对象,提取特定字段
return result.data || result;
} else {
// 其他类型,直接返回
return result;
}
}
// 场景3:深度类型检查
function deepTypeCheck(obj, expectedType) {
const actualType = Type.getType(obj);
if (actualType !== expectedType) {
throw new Error(`Expected type ${expectedType}, got ${actualType}`);
}
// 对于对象,可以递归检查属性
if (actualType === 'object') {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
// 这里可以根据需要递归检查属性类型
console.log(`Property ${key} is of type ${Type.getType(obj[key])}`);
}
}
}
return true;
}
四、Array.isArray()
4.1 基本用法
Array.isArray() 是专门用于判断数组的方法,它比 instanceof 更可靠。
// 基本判断
console.log(Array.isArray([])); // true
console.log(Array.isArray([1, 2, 3])); // true
console.log(Array.isArray(new Array())); // true
console.log(Array.isArray({})); // false
console.log(Array.isArray(null)); // false
console.log(Array.isArray(undefined)); // false
// 跨iframe判断
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = iframe.contentWindow.Array;
const arr = new iframeArray();
console.log(Array.isArray(arr)); // true (跨iframe也能正确判断)
4.2 与 instanceof 的对比
Array.isArray() 在跨框架场景下比 instanceof 更可靠:
// 跨iframe对比
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = iframe.contentWindow.Array;
const arr = new iframeArray();
console.log(arr instanceof Array); // false (跨iframe失败)
console.log(Array.isArray(arr)); // true (跨iframe成功)
4.3 实际应用场景
Array.isArray() 适合用于:
- 数组验证:验证输入是否为数组
- 数据处理:处理可能为数组或类数组的对象
- 跨框架应用:在iframe或Web Worker中处理数组
// 场景1:处理可变参数
function sum() {
const args = Array.isArray(arguments) ? arguments : Array.from(arguments);
return args.reduce((acc, val) => acc + val, 0);
}
// 场景2:数据转换
function normalizeData(data) {
if (Array.isArray(data)) {
return data;
} else if (data && typeof data === 'object') {
// 将对象转换为数组
return Object.values(data);
} else {
return [data];
}
}
// 场景3:React组件属性验证
function MyComponent({ items }) {
if (!Array.isArray(items)) {
console.warn('items prop should be an array');
return null;
}
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
五、ES6+ 新增方法
5.1 Number.isNaN()
Number.isNaN() 比全局 isNaN() 更严格,只在参数为 NaN 时返回 true。
// 对比全局 isNaN()
console.log(isNaN('hello')); // true (字符串被转换为数字,结果是NaN)
console.log(Number.isNaN('hello')); // false (不是NaN)
console.log(isNaN(NaN)); // true
console.log(Number.isNaN(NaN)); // true
console.log(isNaN(undefined)); // true (undefined转换为数字是NaN)
console.log(Number.isNaN(undefined)); // false
5.2 Number.isFinite()
Number.isFinite() 判断一个值是否是有限的数字。
console.log(Number.isFinite(42)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(-Infinity)); // false
console.log(Number.isFinite(NaN)); // false
console.log(Number.isFinite('42')); // false (字符串不是数字)
console.log(Number.isFinite(null)); // false (null不是数字)
5.3 Object.is()
Object.is() 用于判断两个值是否严格相等,它解决了 === 的一些特殊情况。
// 与 === 的对比
console.log(Object.is(NaN, NaN)); // true (=== 返回 false)
console.log(Object.is(0, -0)); // false (=== 返回 true)
console.log(Object.is(0, 0)); // true
console.log(Object.is(undefined, null)); // false
console.log(Object.is(null, null)); // true
5.4 实际应用场景
ES6+ 方法适合用于:
- 数值验证:精确验证数字类型
- 特殊值比较:处理
NaN和0的特殊情况 - 数据清洗:在数据处理中过滤无效值
// 场景1:数据清洗
function cleanData(data) {
return data.filter(item => {
// 只保留有限数字
return Number.isFinite(item);
});
}
// 场景2:处理用户输入
function validateNumberInput(input) {
const num = Number(input);
if (Number.isNaN(num)) {
return { valid: false, error: '输入不是有效数字' };
}
if (!Number.isFinite(num)) {
return { valid: false, error: '数字超出范围' };
}
return { valid: true, value: num };
}
// 场景3:比较特殊值
function compareValues(a, b) {
if (Object.is(a, b)) {
return '严格相等';
} else if (a === b) {
return '宽松相等';
} else {
return '不相等';
}
}
六、自定义类型判断函数
6.1 综合类型判断工具
结合多种方法创建一个全面的类型判断工具:
class TypeChecker {
// 基本类型判断
static isNumber(value) {
return typeof value === 'number' && !Number.isNaN(value);
}
static isString(value) {
return typeof value === 'string';
}
static isBoolean(value) {
return typeof value === 'boolean';
}
static isNull(value) {
return value === null;
}
static isUndefined(value) {
return value === undefined;
}
static isSymbol(value) {
return typeof value === 'symbol';
}
static isBigInt(value) {
return typeof value === 'bigint';
}
// 引用类型判断
static isArray(value) {
return Array.isArray(value);
}
static isObject(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
static isFunction(value) {
return typeof value === 'function';
}
static isDate(value) {
return value instanceof Date && !isNaN(value.getTime());
}
static isRegExp(value) {
return value instanceof RegExp;
}
static isSet(value) {
return value instanceof Set;
}
static isMap(value) {
return value instanceof Map;
}
static isPromise(value) {
return value instanceof Promise ||
(value && typeof value.then === 'function' && typeof value.catch === 'function');
}
// 特殊判断
static isNaN(value) {
return Number.isNaN(value);
}
static isFinite(value) {
return Number.isFinite(value);
}
static isPrimitive(value) {
return value === null ||
(typeof value !== 'object' && typeof value !== 'function');
}
static isPlainObject(value) {
if (!TypeChecker.isObject(value)) return false;
const proto = Object.getPrototypeOf(value);
if (proto === null) return true;
const Ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') &&
proto.constructor;
return typeof Ctor === 'function' &&
Ctor instanceof Function &&
Ctor.toString() === Object.prototype.toString.call(Object);
}
// 类型守卫
static isType(value, type) {
switch (type) {
case 'number': return this.isNumber(value);
case 'string': return this.isString(value);
case 'boolean': return this.isBoolean(value);
case 'null': return this.isNull(value);
case 'undefined': return this.isUndefined(value);
case 'symbol': return this.isSymbol(value);
case 'bigint': return this.isBigInt(value);
case 'array': return this.isArray(value);
case 'object': return this.isObject(value);
case 'function': return this.isFunction(value);
case 'date': return this.isDate(value);
case 'regexp': return this.isRegExp(value);
case 'set': return this.isSet(value);
case 'map': return this.isMap(value);
case 'promise': return this.isPromise(value);
default: return false;
}
}
}
// 使用示例
console.log(TypeChecker.isNumber(42)); // true
console.log(TypeChecker.isObject({})); // true
console.log(TypeChecker.isArray([])); // true
console.log(TypeChecker.isPlainObject({})); // true
console.log(TypeChecker.isPlainObject([])); // false
console.log(TypeChecker.isType([], 'array')); // true
6.2 实际应用场景
自定义类型判断工具适合用于:
- 大型项目:需要统一类型判断标准
- 数据验证:复杂的表单验证
- API开发:验证请求和响应数据
// 场景1:表单验证
function validateForm(formData) {
const errors = [];
if (!TypeChecker.isString(formData.name) || formData.name.trim() === '') {
errors.push('Name must be a non-empty string');
}
if (!TypeChecker.isNumber(formData.age) || formData.age < 0) {
errors.push('Age must be a positive number');
}
if (!TypeChecker.isArray(formData.hobbies) || formData.hobbies.length === 0) {
errors.push('Hobbies must be a non-empty array');
}
if (!TypeChecker.isEmail(formData.email)) {
errors.push('Invalid email format');
}
return {
isValid: errors.length === 0,
errors
};
}
// 场景2:API数据处理
class ApiClient {
constructor(baseURL) {
this.baseURL = baseURL;
}
async request(endpoint, options = {}) {
const response = await fetch(`${this.baseURL}${endpoint}`, options);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
// 验证响应数据
if (!TypeChecker.isObject(data)) {
throw new Error('API response must be an object');
}
if (!TypeChecker.isString(data.status)) {
throw new Error('API response must have a status field');
}
if (data.status !== 'success') {
throw new Error(`API error: ${data.message || 'Unknown error'}`);
}
return data.data;
}
}
// 场景3:配置验证
function validateConfig(config) {
const requiredTypes = {
apiUrl: 'string',
timeout: 'number',
retries: 'number',
cache: 'boolean',
headers: 'object'
};
const errors = [];
for (const [key, expectedType] of Object.entries(requiredTypes)) {
if (!TypeChecker.isType(config[key], expectedType)) {
errors.push(`Config.${key} must be of type ${expectedType}`);
}
}
if (errors.length > 0) {
throw new Error(`Configuration validation failed:\n${errors.join('\n')}`);
}
return true;
}
七、性能比较与最佳实践
7.1 性能比较
不同方法的性能差异:
// 性能测试函数
function performanceTest() {
const iterations = 1000000;
const testValue = [1, 2, 3];
console.time('typeof');
for (let i = 0; i < iterations; i++) {
typeof testValue;
}
console.timeEnd('typeof');
console.time('instanceof');
for (let i = 0; i < iterations; i++) {
testValue instanceof Array;
}
console.timeEnd('instanceof');
console.time('Array.isArray');
for (let i = 0; i < iterations; i++) {
Array.isArray(testValue);
}
console.timeEnd('Array.isArray');
console.time('Object.prototype.toString.call');
for (let i = 0; i < iterations; i++) {
Object.prototype.toString.call(testValue);
}
console.timeEnd('Object.prototype.toString.call');
}
// 典型性能结果(Chrome 90+):
// typeof: ~5ms
// instanceof: ~10ms
// Array.isArray: ~8ms
// Object.prototype.toString.call: ~15ms
7.2 最佳实践总结
7.2.1 方法选择指南
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 检查变量是否为函数 | typeof |
最快,专门用于函数检测 |
| 检查变量是否为数组 | Array.isArray() |
最可靠,跨框架兼容 |
| 检查自定义类实例 | instanceof |
检查原型链,适合继承关系 |
| 精确类型判断 | Object.prototype.toString.call() |
最准确,区分所有类型 |
| 检查数字有效性 | Number.isFinite() / Number.isNaN() |
严格验证数字 |
| 大型项目类型判断 | 自定义工具类 | 统一标准,易于维护 |
7.2.2 代码示例:综合应用
// 综合类型判断工具
function getType(value) {
// 特殊值处理
if (value === null) return 'null';
if (value === undefined) return 'undefined';
// 基本类型
const type = typeof value;
if (type !== 'object') return type;
// 引用类型
if (Array.isArray(value)) return 'array';
if (value instanceof Date) return 'date';
if (value instanceof RegExp) return 'regexp';
if (value instanceof Set) return 'set';
if (value instanceof Map) return 'map';
if (value instanceof Promise) return 'promise';
// 普通对象
return 'object';
}
// 类型守卫函数
function isType(value, type) {
const actualType = getType(value);
return actualType === type;
}
// 使用示例
function processData(data) {
const type = getType(data);
switch (type) {
case 'array':
return data.map(item => processItem(item));
case 'object':
return Object.keys(data).reduce((acc, key) => {
acc[key] = processItem(data[key]);
return acc;
}, {});
case 'string':
return data.trim();
case 'number':
return Number.isFinite(data) ? data : 0;
case 'null':
case 'undefined':
return '';
default:
return data;
}
}
八、常见陷阱与解决方案
8.1 常见陷阱
8.1.1 typeof null 问题
// 陷阱:typeof null 返回 "object"
console.log(typeof null); // "object"
// 解决方案:使用严格相等
function isNull(value) {
return value === null;
}
// 或者使用自定义工具
function isNull(value) {
return Object.prototype.toString.call(value) === '[object Null]';
}
8.1.2 跨框架问题
// 陷阱:instanceof 在跨iframe时失效
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = iframe.contentWindow.Array;
const arr = new iframeArray();
console.log(arr instanceof Array); // false
// 解决方案:使用 Array.isArray() 或 Object.prototype.toString.call()
console.log(Array.isArray(arr)); // true
console.log(Object.prototype.toString.call(arr)); // "[object Array]"
8.1.3 类数组对象
// 陷阱:类数组对象不是真正的数组
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
console.log(Array.isArray(arrayLike)); // false
// 解决方案:使用 Array.from() 或展开运算符
const realArray = Array.from(arrayLike); // ['a', 'b']
const realArray2 = [...arrayLike]; // ['a', 'b'] (需要可迭代)
8.2 解决方案示例
// 完整的类型判断解决方案
class TypeUtils {
// 检查是否为null
static isNull(value) {
return value === null;
}
// 检查是否为undefined
static isUndefined(value) {
return value === undefined;
}
// 检查是否为null或undefined
static isNullOrUndefined(value) {
return value == null; // 使用宽松相等
}
// 检查是否为数组
static isArray(value) {
return Array.isArray(value);
}
// 检查是否为类数组
static isArrayLike(value) {
if (value == null) return false;
const length = value.length;
return typeof length === 'number' &&
length >= 0 &&
length % 1 === 0 &&
length <= Number.MAX_SAFE_INTEGER;
}
// 检查是否为可迭代对象
static isIterable(value) {
return value != null && typeof value[Symbol.iterator] === 'function';
}
// 检查是否为纯对象(非数组、非函数、非日期等)
static isPlainObject(value) {
if (!TypeUtils.isObject(value)) return false;
const proto = Object.getPrototypeOf(value);
if (proto === null) return true;
const Ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') &&
proto.constructor;
return typeof Ctor === 'function' &&
Ctor instanceof Function &&
Ctor.toString() === Object.prototype.toString.call(Object);
}
// 检查是否为对象(非null)
static isObject(value) {
return value !== null && typeof value === 'object';
}
// 检查是否为函数
static isFunction(value) {
return typeof value === 'function';
}
// 检查是否为数字
static isNumber(value) {
return typeof value === 'number' && !Number.isNaN(value);
}
// 检查是否为有限数字
static isFiniteNumber(value) {
return typeof value === 'number' && Number.isFinite(value);
}
// 检查是否为字符串
static isString(value) {
return typeof value === 'string';
}
// 检查是否为布尔值
static isBoolean(value) {
return typeof value === 'boolean';
}
// 检查是否为Symbol
static isSymbol(value) {
return typeof value === 'symbol';
}
// 检查是否为BigInt
static isBigInt(value) {
return typeof value === 'bigint';
}
// 检查是否为Date
static isDate(value) {
return value instanceof Date && !isNaN(value.getTime());
}
// 检查是否为RegExp
static isRegExp(value) {
return value instanceof RegExp;
}
// 检查是否为Set
static isSet(value) {
return value instanceof Set;
}
// 检查是否为Map
static isMap(value) {
return value instanceof Map;
}
// 检查是否为Promise
static isPromise(value) {
return value instanceof Promise ||
(value && typeof value.then === 'function' && typeof value.catch === 'function');
}
// 获取类型字符串
static getType(value) {
if (value === null) return 'null';
if (value === undefined) return 'undefined';
const type = typeof value;
if (type !== 'object') return type;
if (Array.isArray(value)) return 'array';
if (value instanceof Date) return 'date';
if (value instanceof RegExp) return 'regexp';
if (value instanceof Set) return 'set';
if (value instanceof Map) return 'map';
if (value instanceof Promise) return 'promise';
return 'object';
}
// 类型守卫
static isType(value, type) {
return this.getType(value) === type;
}
}
// 使用示例
console.log(TypeUtils.isNull(null)); // true
console.log(TypeUtils.isUndefined(undefined)); // true
console.log(TypeUtils.isArray([])); // true
console.log(TypeUtils.isArrayLike({ 0: 'a', 1: 'b', length: 2 })); // true
console.log(TypeUtils.isPlainObject({})); // true
console.log(TypeUtils.isPlainObject([])); // false
console.log(TypeUtils.getType([])); // "array"
九、总结
JavaScript中判断变量类型的方法多种多样,每种方法都有其适用场景和局限性。在实际开发中,应根据具体需求选择合适的方法:
- 快速检查基本类型:使用
typeof,特别是检查undefined和函数 - 数组判断:优先使用
Array.isArray(),确保跨框架兼容性 - 自定义类实例判断:使用
instanceof,检查原型链 - 精确类型判断:使用
Object.prototype.toString.call(),区分所有类型 - 数值验证:使用
Number.isFinite()和Number.isNaN() - 大型项目:创建自定义类型判断工具,统一标准
记住,没有一种方法是完美的,理解每种方法的原理和适用场景,才能在实际开发中做出最佳选择。通过合理组合这些方法,可以构建出健壮、可靠的类型判断系统,提高代码质量和可维护性。
