在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 适合用于:

  1. 快速检查基本类型:特别是检查变量是否为 undefined
  2. 函数检测:判断变量是否为函数
  3. 性能敏感场景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)场景下可能失效
  • 无法判断 nullundefined
// 无法判断基本类型
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. 自定义类实例判断:判断对象是否为特定类的实例
  2. 原型链检查:检查继承关系
  3. 框架内对象判断:在单一框架内判断内置对象类型
// 场景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() 适合用于:

  1. 精确类型判断:需要区分具体对象类型时
  2. 类型守卫:在TypeScript中作为类型守卫
  3. 数据验证:验证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() 适合用于:

  1. 数组验证:验证输入是否为数组
  2. 数据处理:处理可能为数组或类数组的对象
  3. 跨框架应用:在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+ 方法适合用于:

  1. 数值验证:精确验证数字类型
  2. 特殊值比较:处理 NaN0 的特殊情况
  3. 数据清洗:在数据处理中过滤无效值
// 场景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 实际应用场景

自定义类型判断工具适合用于:

  1. 大型项目:需要统一类型判断标准
  2. 数据验证:复杂的表单验证
  3. 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中判断变量类型的方法多种多样,每种方法都有其适用场景和局限性。在实际开发中,应根据具体需求选择合适的方法:

  1. 快速检查基本类型:使用 typeof,特别是检查 undefined 和函数
  2. 数组判断:优先使用 Array.isArray(),确保跨框架兼容性
  3. 自定义类实例判断:使用 instanceof,检查原型链
  4. 精确类型判断:使用 Object.prototype.toString.call(),区分所有类型
  5. 数值验证:使用 Number.isFinite()Number.isNaN()
  6. 大型项目:创建自定义类型判断工具,统一标准

记住,没有一种方法是完美的,理解每种方法的原理和适用场景,才能在实际开发中做出最佳选择。通过合理组合这些方法,可以构建出健壮、可靠的类型判断系统,提高代码质量和可维护性。