【前端面试小册】JS-第27节:实现类型判断

一、核心概念

1.1 为什么需要类型判断

JavaScript 是动态类型语言,变量的类型在运行时才能确定。准确判断变量类型对于:

  • 参数验证
  • 错误处理
  • 类型转换
  • 代码健壮性

都非常重要。

1.2 类型判断方法对比

方法 优点 缺点 适用场景
typeof 简单快速 无法区分对象类型 基本类型判断
instanceof 判断实例 无法判断基本类型 对象实例判断
Object.prototype.toString 最准确 语法稍复杂 精确类型判断

二、实现类型判断

2.1 基础实现

// 获取类型
const getType = (type) => {
    return Object.prototype.toString.call(type).match(/\s+(\w+)/)[1];
};

2.2 原理解析

let type = function() {};
Object.prototype.toString.call(type);  // "[object Function]"
match(/\s+(\w+)/)[1];                  // 匹配的就是空格后面的 Function

关键点

  • Object.prototype.toString.call() 返回格式:[object Type]
  • 使用正则表达式 /\s+(\w+)/ 提取类型名
  • [1] 获取第一个捕获组(类型名)

2.3 执行流程

graph TD
    A[调用 getType] --> B[Object.prototype.toString.call]
    B --> C[返回 object Type 字符串]
    C --> D[正则匹配]
    D --> E[提取类型名]
    E --> F[返回类型]

三、测试用例

3.1 各种类型测试

let type1 = function() {};
let type2 = undefined;
let type3 = null;
let type4 = {};
let type5 = false;
let type6 = '5';
let type7 = 5;
let type8 = [];
let type9 = Symbol('id');
let type10 = BigInt(10);
let type11 = /test/g;
let type12 = new Date();
let type13 = new Map();
let type14 = new Set();

console.log(getType(type1));   // Function
console.log(getType(type2));   // Undefined
console.log(getType(type3));   // Null
console.log(getType(type4));   // Object
console.log(getType(type5));   // Boolean
console.log(getType(type6));   // String
console.log(getType(type7));   // Number
console.log(getType(type8));   // Array
console.log(getType(type9));   // Symbol
console.log(getType(type10));  // BigInt
console.log(getType(type11));  // RegExp
console.log(getType(type12));  // Date
console.log(getType(type13));  // Map
console.log(getType(type14));  // Set

四、增强版本

4.1 支持类型检查函数

// 获取类型
const getType = (type) => {
    return Object.prototype.toString.call(type).match(/\s+(\w+)/)[1];
};

// 类型检查函数
const isType = (value, type) => {
    return getType(value).toLowerCase() === type.toLowerCase();
};

// 测试
console.log(isType(23, 'number'));        // true
console.log(isType('愚公上岸说', 'string')); // true
console.log(isType([], 'array'));         // true
console.log(isType({}, 'object'));        // true
console.log(isType(null, 'null'));        // true

4.2 完整工具函数

class TypeChecker {
    // 获取类型
    static getType(value) {
        return Object.prototype.toString.call(value).match(/\s+(\w+)/)[1];
    }
    
    // 类型检查
    static isType(value, type) {
        return this.getType(value).toLowerCase() === type.toLowerCase();
    }
    
    // 具体类型判断方法
    static isString(value) {
        return this.isType(value, 'string');
    }
    
    static isNumber(value) {
        return this.isType(value, 'number') && !isNaN(value);
    }
    
    static isArray(value) {
        return this.isType(value, 'array');
    }
    
    static isObject(value) {
        return this.isType(value, 'object') && value !== null;
    }
    
    static isFunction(value) {
        return this.isType(value, 'function');
    }
    
    static isNull(value) {
        return this.isType(value, 'null');
    }
    
    static isUndefined(value) {
        return this.isType(value, 'undefined');
    }
    
    static isBoolean(value) {
        return this.isType(value, 'boolean');
    }
    
    static isSymbol(value) {
        return this.isType(value, 'symbol');
    }
    
    static isBigInt(value) {
        return this.isType(value, 'bigint');
    }
    
    static isDate(value) {
        return this.isType(value, 'date');
    }
    
    static isRegExp(value) {
        return this.isType(value, 'regexp');
    }
    
    static isMap(value) {
        return this.isType(value, 'map');
    }
    
    static isSet(value) {
        return this.isType(value, 'set');
    }
    
    static isPromise(value) {
        return this.isType(value, 'promise') || 
               (this.isObject(value) && 
                typeof value.then === 'function' && 
                typeof value.catch === 'function');
    }
}

// 使用示例
console.log(TypeChecker.isString('hello'));     // true
console.log(TypeChecker.isNumber(123));         // true
console.log(TypeChecker.isArray([1, 2, 3]));    // true
console.log(TypeChecker.isObject({}));          // true
console.log(TypeChecker.isNull(null));          // true

五、特殊类型判断

5.1 判断是否为纯对象

function isPlainObject(value) {
    if (TypeChecker.getType(value) !== 'Object') {
        return false;
    }
    
    // 检查是否有原型
    if (Object.getPrototypeOf(value) === null) {
        return true;
    }
    
    // 检查原型链
    let proto = value;
    while (Object.getPrototypeOf(proto) !== null) {
        proto = Object.getPrototypeOf(proto);
    }
    
    return Object.getPrototypeOf(value) === proto;
}

// 测试
console.log(isPlainObject({}));           // true
console.log(isPlainObject(new Object())); // true
console.log(isPlainObject([]));           // false
console.log(isPlainObject(null));         // false

5.2 判断是否为类数组

function isArrayLike(value) {
    if (value == null || typeof value === 'function') {
        return false;
    }
    
    const length = value.length;
    return typeof length === 'number' && 
           length >= 0 && 
           length < Number.MAX_SAFE_INTEGER;
}

// 测试
console.log(isArrayLike([1, 2, 3]));        // true
console.log(isArrayLike('hello'));          // true
console.log(isArrayLike({ length: 3 }));    // true
console.log(isArrayLike({ length: -1 }));   // false
console.log(isArrayLike(null));             // false

5.3 判断是否为空值

function isEmpty(value) {
    if (value == null) {
        return true;
    }
    
    if (TypeChecker.isArray(value) || TypeChecker.isString(value)) {
        return value.length === 0;
    }
    
    if (TypeChecker.isObject(value)) {
        return Object.keys(value).length === 0;
    }
    
    if (TypeChecker.isMap(value) || TypeChecker.isSet(value)) {
        return value.size === 0;
    }
    
    return false;
}

// 测试
console.log(isEmpty(null));        // true
console.log(isEmpty(undefined));   // true
console.log(isEmpty(''));          // true
console.log(isEmpty([]));          // true
console.log(isEmpty({}));         // true
console.log(isEmpty(new Map()));  // true
console.log(isEmpty(new Set()));  // true

六、实际应用场景

6.1 参数验证

function processData(data) {
    if (!TypeChecker.isObject(data)) {
        throw new TypeError('data must be an object');
    }
    
    if (!TypeChecker.isString(data.name)) {
        throw new TypeError('data.name must be a string');
    }
    
    if (!TypeChecker.isNumber(data.age)) {
        throw new TypeError('data.age must be a number');
    }
    
    // 处理数据
    return `Name: ${data.name}, Age: ${data.age}`;
}

6.2 类型转换

function safeParse(value, defaultValue) {
    if (TypeChecker.isString(value)) {
        try {
            return JSON.parse(value);
        } catch (e) {
            return defaultValue;
        }
    }
    return defaultValue;
}

6.3 深拷贝类型判断

function deepClone(value) {
    const type = TypeChecker.getType(value);
    
    if (type === 'Array') {
        return value.map(item => deepClone(item));
    }
    
    if (type === 'Object') {
        const cloned = {};
        for (let key in value) {
            if (value.hasOwnProperty(key)) {
                cloned[key] = deepClone(value[key]);
            }
        }
        return cloned;
    }
    
    if (type === 'Date') {
        return new Date(value.getTime());
    }
    
    if (type === 'RegExp') {
        return new RegExp(value.source, value.flags);
    }
    
    return value;
}

七、面试要点总结

核心知识点

  1. Object.prototype.toString:最准确的类型判断方法
  2. 正则提取:使用正则表达式提取类型名
  3. 类型检查:提供便捷的类型检查函数
  4. 特殊类型:处理纯对象、类数组等特殊情况

常见面试题

Q1: 如何准确判断 JavaScript 中的类型?

答:使用 Object.prototype.toString.call() 方法,它返回 [object Type] 格式的字符串,可以准确判断所有类型。

Q2: typeof 和 Object.prototype.toString 的区别?

答:

  • typeof:简单快速,但无法区分对象类型(数组、日期等)
  • Object.prototype.toString:最准确,可以区分所有类型

Q3: 如何判断一个值是否为数组?

答:

  • Array.isArray(value)(推荐)
  • Object.prototype.toString.call(value) === '[object Array]'
  • value instanceof Array(不推荐,跨框架可能失效)

实战建议

  • ✅ 理解各种类型判断方法的优缺点
  • ✅ 掌握 Object.prototype.toString 的使用
  • ✅ 在实际项目中封装类型判断工具函数
  • ✅ 注意特殊类型的处理(null、undefined、NaN 等)
#前端面试##百度##滴滴##银行##前端#
前端面试小册 文章被收录于专栏

每天更新3-4节,持续更新中... 目标:50天学完,上岸银行总行!

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务