JavaScript_类型

JavaScript 是一种动态类型语言,变量没有静态类型,但值有类型。理解 JavaScript 的类型系统及其判断方式是编写高质量代码的基础。


一、JavaScript 数据类型分类

1. 基本类型(Primitive Types)

  • 数值(Number):包括整数和浮点数,如 423.14
  • 字符串(String):文本值,如 "hello"
  • 布尔值(Boolean)truefalse
  • 空值(Null):只有一个值 null,表示有意为空
  • 未定义(Undefined):变量声明但未赋值时的默认值
  • 符号(Symbol):ES6 新增,唯一且不可变的值
  • 大整数(BigInt):ES2020 新增,用于表示任意大的整数

2. 引用类型(Reference Types)

  • 对象(Object):最基本的引用类型
  • 数组(Array):有序的数据集合
  • 函数(Function):可执行的代码块
  • 日期(Date):处理日期和时间
  • 正则表达式(RegExp):处理文本模式匹配
  • 其他内置对象:如 Map、Set、WeakMap、WeakSet 等

二、类型判断方法

1. typeof 操作符

  • 适用场景:基本类型(除 null)和函数
  • 局限性:无法区分对象、数组、日期等引用类型
typeof 42; // "number"
typeof 'hello'; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof 123n; // "bigint"
typeof function () {}; // "function"

// 特殊情况
typeof null; // "object"(历史遗留问题)
typeof []; // "object"
typeof new Date(); // "object"
typeof /abc/; // "object"

2. instanceof 操作符

  • 适用场景:判断对象是否是某个构造函数的实例
  • 局限性:无法判断基本类型,且受原型链影响
[] instanceof Array; // true
[] instanceof Object; // true(数组继承自 Object)
new Date() instanceof Date; // true
new Date() instanceof Object; // true

// 基本类型使用 instanceof 无效
'hello' instanceof String; // false(基本类型不是对象)
new String('hello') instanceof String; // true(包装对象)

3. Object.prototype.toString.call()

  • 适用场景:精确判断所有内置类型
  • 返回格式[object Type],其中 Type 是具体类型
Object.prototype.toString.call(42); // "[object Number]"
Object.prototype.toString.call('hello'); // "[object String]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(Symbol()); // "[object Symbol]"
Object.prototype.toString.call(123n); // "[object BigInt]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call(new Date()); // "[object Date]"
Object.prototype.toString.call(function () {}); // "[object Function]"
Object.prototype.toString.call(/abc/); // "[object RegExp]"
Object.prototype.toString.call(new Map()); // "[object Map]"

4. Array.isArray()

  • 适用场景:专门判断是否为数组
  • 等价于Object.prototype.toString.call(value) === '[object Array]'
Array.isArray([]); // true
Array.isArray({}); // false
Array.isArray(new Array()); // true

5. 自定义类型检查函数

  • 适用场景:封装常用类型判断逻辑
function isNumber(value) {
  return typeof value === 'number' && !isNaN(value);
}

function isString(value) {
  return typeof value === 'string';
}

function isNull(value) {
  return value === null;
}

function isUndefined(value) {
  return value === undefined;
}

function isNullOrUndefined(value) {
  return value === null || value === undefined;
}

function isObject(value) {
  return value !== null && typeof value === 'object';
}

function isPlainObject(value) {
  return Object.prototype.toString.call(value) === '[object Object]';
}

6. ES6+ 新增方法

  • Number.isNaN():判断是否为 NaN(比全局 isNaN 更严格)
  • Number.isFinite():判断是否为有限数
  • Number.isInteger():判断是否为整数
  • String.prototype.isPrototypeOf():判断是否为字符串原型
Number.isNaN(NaN); // true
Number.isNaN('NaN'); // false(全局 isNaN 会返回 true)

Number.isFinite(42); // true
Number.isFinite(Infinity); // false

Number.isInteger(42); // true
Number.isInteger(3.14); // false

三、类型判断的注意事项

1. 包装对象与基本类型

typeof new String('hello'); // "object"
typeof 'hello'; // "string"

// 推荐使用基本类型进行比较
'hello' === 'hello'; // true
new String('hello') === new String('hello'); // false(不同对象引用)

2. 跨窗口/iframe 对象

  • instanceof 在跨窗口环境中可能失效,因为每个窗口有自己的构造函数
  • 推荐使用 Array.isArray()Object.prototype.toString.call()
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const array = iframe.contentWindow.Array;
const arr = new array();

arr instanceof Array; // false(不同窗口的 Array 构造函数)
Array.isArray(arr); // true
Object.prototype.toString.call(arr); // "[object Array]"

3. 类数组对象

  • 类数组对象有 length 属性但没有数组方法
  • 常见类数组:arguments、DOM 节点列表
function test() {
  console.log(Array.isArray(arguments)); // false
  console.log(Object.prototype.toString.call(arguments)); // "[object Arguments]"
}

四、面试高频问题

  1. JavaScript 有哪些数据类型?
    答:JavaScript 分为基本类型(Number、String、Boolean、Null、Undefined、Symbol、BigInt)和引用类型(Object、Array、Function 等)。

  2. 如何准确判断一个变量是否为数组?
    答:推荐使用 Array.isArray()Object.prototype.toString.call(value) === '[object Array]'。避免使用 typeof,因为它对数组返回 "object"

  3. typeof null 为什么返回 "object"?
    答:这是 JavaScript 语言的历史遗留问题。早期 JavaScript 内部用标记位表示类型,null 的标记位与对象相同,导致误判。

  4. instanceof 和 Object.prototype.toString.call() 的区别是什么?
    答:

    • instanceof 检查对象是否是某个构造函数的实例,受原型链影响
    • Object.prototype.toString.call() 返回对象的内部类型标签,更精确
    • 跨窗口环境中,instanceof 可能失效,而 Object.prototype.toString.call() 依然可靠
  5. 如何判断一个值是 NaN?
    答:使用 Number.isNaN() 而不是全局 isNaN()Number.isNaN() 只对真正的 NaN 返回 true,而全局 isNaN() 会将无法转换为数字的值(如字符串)也视为 NaN

五、实用工具函数

以下是一个综合的类型判断工具库示例:

const TypeUtils = {
  isNumber(value) {
    return typeof value === 'number' && !isNaN(value);
  },

  isString(value) {
    return typeof value === 'string';
  },

  isBoolean(value) {
    return typeof value === 'boolean';
  },

  isNull(value) {
    return value === null;
  },

  isUndefined(value) {
    return value === undefined;
  },

  isNullOrUndefined(value) {
    return value === null || value === undefined;
  },

  isObject(value) {
    return value !== null && typeof value === 'object';
  },

  isPlainObject(value) {
    return Object.prototype.toString.call(value) === '[object Object]';
  },

  isArray(value) {
    return Array.isArray(value);
  },

  isFunction(value) {
    return typeof value === 'function';
  },

  isDate(value) {
    return Object.prototype.toString.call(value) === '[object Date]';
  },

  isRegExp(value) {
    return Object.prototype.toString.call(value) === '[object RegExp]';
  },

  isSymbol(value) {
    return typeof value === 'symbol';
  },

  isBigInt(value) {
    return typeof value === 'bigint';
  },

  isNaN(value) {
    return Number.isNaN(value);
  },

  isFinite(value) {
    return Number.isFinite(value);
  },

  isInteger(value) {
    return Number.isInteger(value);
  },

  isEmpty(value) {
    if (this.isNullOrUndefined(value)) return true;
    if (this.isArray(value) || this.isString(value)) return value.length === 0;
    if (this.isPlainObject(value)) return Object.keys(value).length === 0;
    return false;
  },
};

总结

JavaScript 的类型系统既灵活又复杂,掌握正确的类型判断方法至关重要。在实际开发中,推荐根据场景选择合适的判断方式:

  • 基本类型判断:优先使用 typeof
  • 数组判断:使用 Array.isArray()
  • 精确类型判断:使用 Object.prototype.toString.call()
  • 自定义类型:使用 instanceof 或类的静态方法

避免常见的类型判断陷阱,如 typeof null 的误判、包装对象与基本类型的混淆,以及跨窗口环境下的 instanceof 失效问题。通过合理运用类型判断技术,可以编写出更健壮、更安全的 JavaScript 代码。

Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""