JavaScript数据类型及判断方法详解

JavaScript 数据类型及判断方法详解

前言

JavaScript 是一种动态类型语言,理解其数据类型及如何准确判断类型是每个前端开发者的必备技能。本文将详细介绍 JavaScript 的七种数据类型以及各种类型判断方法的优缺点和使用场景。

一、JavaScript 的七种数据类型

JavaScript 共有七种数据类型,分为两大类:基本类型和引用类型。

1. 基本类型(原始类型)

  • Undefined:表示未定义,只有一个值undefined
  • Null:表示空值,只有一个值null
  • Boolean:布尔值,有两个值truefalse
  • Number:数字类型,包括整数和浮点数
  • String:字符串类型
  • Symbol:符号类型(ES6 新增)
  • BigInt:大整数类型(ES2020 新增)

2. 引用类型

  • Object:对象类型,包括普通对象、数组、函数、日期、正则表达式等

二、类型判断方法

1. typeof 操作符

typeof是最基本的类型判断方法,返回一个表示数据类型的字符串。

1
2
3
4
5
6
7
8
9
10
typeof undefined; // "undefined"
typeof null; // "object" (这是一个历史遗留的bug)
typeof true; // "boolean"
typeof 42; // "number"
typeof "hello"; // "string"
typeof Symbol(); // "symbol"
typeof 123n; // "bigint"
typeof {}; // "object"
typeof []; // "object"
typeof function () {}; // "function"

优点

  • 简单直接
  • 可以区分基本类型(除了 null)

缺点

  • 对于 null 返回”object”(历史遗留问题)
  • 无法区分对象和数组
  • 对于所有引用类型(除函数外)都返回”object”

2. instanceof 操作符

instanceof用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。

1
2
3
4
5
[] instanceof Array        // true
[] instanceof Object // true
{} instanceof Object // true
{} instanceof Array // false
function(){} instanceof Function // true

优点

  • 可以区分不同的引用类型
  • 可以检测自定义类型

缺点

  • 不能用于判断基本类型
  • 跨 iframe 或 window 时可能失效
  • 原型链可以被修改,导致判断不准确

3. Object.prototype.toString.call()

这是最准确的类型判断方法,返回[object Type]格式的字符串。

1
2
3
4
5
6
7
8
9
10
11
12
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(123n); // "[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(/regex/); // "[object RegExp]"
Object.prototype.toString.call(new Date()); // "[object Date]"

优点

  • 可以准确判断所有类型
  • 不受原型链影响
  • 可以区分内置对象类型

缺点

  • 写法较长
  • 不够直观

4. constructor 属性

每个对象都有一个constructor属性,指向创建该对象的构造函数。

1
2
3
4
(42).constructor === Number     // true
"hello".constructor === String // true
[].constructor === Array // true
{}.constructor === Object // true

优点

  • 可以区分大部分类型
  • 写法相对简洁

缺点

  • null 和 undefined 没有 constructor 属性
  • constructor 可以被修改
  • 原型链继承可能导致判断错误

5. Array.isArray()

专门用于判断是否为数组的方法。

1
2
Array.isArray([]); // true
Array.isArray({}); // false

优点

  • 专门为数组设计,判断准确
  • 不受原型链影响

缺点

  • 只能判断数组

三、最佳实践

1. 封装通用类型判断函数

1
2
3
4
5
6
7
8
9
10
11
12
// 精确的类型判断函数
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

// 使用示例
getType(42); // "number"
getType("hello"); // "string"
getType([]); // "array"
getType({}); // "object"
getType(null); // "null"
getType(undefined); // "undefined"

2. 常用类型判断工具函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 判断是否为null
function isNull(value) {
return value === null;
}

// 判断是否为undefined
function isUndefined(value) {
return value === undefined;
}

// 判断是否为null或undefined
function isNullOrUndefined(value) {
return value == null; // 利用==的特性
}

// 判断是否为数字
function isNumber(value) {
return typeof value === "number" && !isNaN(value);
}

// 判断是否为字符串
function isString(value) {
return typeof value === "string";
}

// 判断是否为布尔值
function isBoolean(value) {
return typeof value === "boolean";
}

// 判断是否为函数
function isFunction(value) {
return typeof value === "function";
}

// 判断是否为数组
function isArray(value) {
return Array.isArray(value);
}

// 判断是否为普通对象
function isPlainObject(value) {
return getType(value) === "object";
}

// 判断是否为Promise
function isPromise(value) {
return getType(value) === "promise";
}

3. 类型判断的选择建议

  • 基本类型判断:使用typeof(除了 null)
  • null 判断:使用value === null
  • 数组判断:使用Array.isArray()
  • 精确类型判断:使用Object.prototype.toString.call()
  • 自定义类型判断:使用instanceof

四、常见陷阱与注意事项

1. typeof null === “object”

这是 JavaScript 的一个历史遗留 bug,在第一版 JavaScript 中,null 被标记为对象类型,虽然后来有了单独的 null 类型,但为了兼容性,这个 bug 被保留了下来。

2. NaN 的特殊性

1
2
3
4
5
typeof NaN === "number"; // true
NaN === NaN; // false
Object.is(NaN, NaN); // true
isNaN(NaN); // true
Number.isNaN(NaN); // true

3. 包装对象的影响

1
2
3
4
5
typeof new String("hello"); // "object"
typeof "hello"; // "string"

new String("hello") instanceof String; // true
"hello" instanceof String; // false

4. 跨 iframe 问题

1
2
3
4
5
6
// 在iframe中创建的数组
const iframeArray = window.frames[0].Array;
const arr = new iframeArray(1, 2, 3);

arr instanceof Array; // false
Array.isArray(arr); // true

五、总结

JavaScript 提供了多种类型判断方法,每种方法都有其适用场景:

  • typeof:适合判断基本类型(除 null 外)
  • instanceof:适合判断引用类型和自定义类型
  • Object.prototype.toString.call():最准确的类型判断方法
  • Array.isArray():专门用于判断数组
  • constructor:可以用于类型判断,但不够可靠

在实际开发中,建议根据具体需求选择合适的判断方法,或者封装成工具函数以提高代码的可读性和可维护性,准确的类型判断是编写健壮 JavaScript 代码的基础。