人人都会AI编程

8.2 八大内置数据类型

更新时间:2026-07-11

在上一节中,我们学习了如何用 varletconst 声明变量。但变量只是容器,真正决定程序行为的是容器里装的东西——数据。JavaScript 中的每一个值都属于某种数据类型,深刻理解这些类型是写出可靠代码的基础。

ECMAScript 标准定义了八种数据类型,分为两大类:基本类型(Primitive)引用类型(Object)。它们的内存存储方式、复制行为、比较规则截然不同。

8.2.1 七大基本类型

基本类型的值直接存储在栈内存中,是按值访问的。当你把一个基本类型的变量赋值给另一个变量时,会复制一份独立的值,二者互不影响。

Undefined

undefined 只有一个值 undefined。它表示变量已声明但未赋值,或者访问对象不存在的属性时的默认返回值。

let a;
console.log(a);          // undefined
const obj = {};
console.log(obj.name);   // undefined

实际开发中,建议不要主动将变量赋值为 undefined,让 undefined 保持“系统默认缺失值”的语义。如果需要显式表示“空”,应该用 null

Null

null 也只有一个值 null。它表示一个空对象指针,通常由开发者主动赋值,表示“这里应该有一个对象,但目前没有”。

let element = document.getElementById('nonexistent');
console.log(element);    // null(找不到元素时返回 null,不是 undefined)

有趣的是,typeof null 返回 "object",这是 JavaScript 早期实现遗留的 bug,至今未修复。判断一个值是否为 null 应该使用严格相等:

if (value === null) { /* ... */ }

Boolean

布尔类型只有两个值:truefalse。常用于条件判断。JavaScript 中的任何值都可以通过 Boolean() 函数转换为布尔值,转换规则如下:

转换为 false 的值(falsy 值)false0-00n(BigInt 零)、""(空字符串)、nullundefinedNaN

其余所有值转换为 true(truthy 值),包括 " "(空格字符串)、[](空数组)、{}(空对象)。

if ("")          { /* 不会执行 */ }
if (" ")         { /* 会执行 */ }
if ([])          { /* 会执行 */ }

Number

JavaScript 的数字类型基于 IEEE 754 双精度浮点数,没有区分整数和浮点数,所有数字都是 64 位双精度格式。这带来两个重要影响:

  1. 数值范围:最大安全整数为 Number.MAX_SAFE_INTEGER(2^53 - 1),最小安全整数为 Number.MIN_SAFE_INTEGER(-(2^53 - 1))。超出安全范围的整数会失去精度。
  1. 浮点数精度问题:某些小数无法用二进制精确表示,会产生舍入误差。
0.1 + 0.2;          // 0.30000000000000004
0.1 + 0.2 === 0.3;  // false

实际开发中处理货币、百分比等需要精确计算的场景,通常转为整数计算(例如以分为单位)或使用专门的库(如 decimal.js)。第 32 章会深入剖析浮点数精度问题与解决方案。

NaN(Not a Number)也属于 Number 类型,它表示一个本来应该返回数字却失败了的结果。NaN 不等于任何值,包括它自己。

typeof NaN;        // "number"
NaN === NaN;       // false
isNaN(NaN);        // true
Number.isNaN(NaN); // true(推荐方式,不会做类型转换)

BigInt

ES2020 引入的 BigInt 解决了 Number 无法安全表示大整数的问题。通过在整数后面加 n 或调用 BigInt() 函数创建。

const big = 9007199254740993n;
const another = BigInt("9007199254740993");
typeof big; // "bigint"

BigInt 不能与 Number 直接混合运算,必须显式转换,但注意转换大数时可能丢失精度。

3n + 5n;     // 8n
3n + 5;      // TypeError: Cannot mix BigInt and other types
Number(9007199254740993n); // 9007199254740992(精度已丢失)

String

字符串用于表示文本,可以用单引号、双引号或反引号(模板字符串)定义。字符串是不可变的,一旦创建就无法修改,所有字符串操作方法都会返回新字符串。

let str = "Hello";
str[0] = "h";       // 非严格模式下静默失败,严格模式下报错
console.log(str);   // "Hello"

模板字符串(反引号)支持多行文本和内嵌表达式,极大提升了复杂字符串的可读性:

const name = "张三";
const greeting = `你好,${name}!
今天天气不错。`;

Symbol

ES6 引入的 Symbol 表示独一无二的值,主要用于创建对象的私有属性或作为常量标识,避免属性名冲突。

const s1 = Symbol("description");
const s2 = Symbol("description");
s1 === s2; // false,即使描述相同也是不同的 Symbol

全局符号可以通过 Symbol.for()Symbol.keyFor() 在全局符号注册表中共享:

const globalSym = Symbol.for("app.key");
Symbol.keyFor(globalSym); // "app.key"

Symbol 不能被自动转换为字符串(会报 TypeError),需要显式调用 toString() 或访问 description 属性。

8.2.2 唯一的引用类型:Object

Object 是一组键值对的无序集合。除了基本的七种类型,其余所有值本质上都是对象。包括:

  • 普通对象 {}
  • 数组 [](也是对象)
  • 函数(可调用的对象)
  • 正则表达式、日期 DateMapSet 等内置对象
  • 类实例

引用类型的值存储在堆内存中,变量保存的只是指向该内存地址的引用(指针)。赋值操作传递的是引用,而不是复制对象本身。

const obj1 = { name: "Alice" };
const obj2 = obj1;       // 传递引用
obj2.name = "Bob";
console.log(obj1.name);  // "Bob",因为指向同一个对象

这也是比较两个对象时需要特别注意的地方——=== 比较的是引用地址,而不是内容。

{} === {};   // false,两个独立的对象
[1,2] === [1,2]; // false

8.2.3 基本类型与引用类型的核心区别总结

| 特性 | 基本类型 | 引用类型 |
|------|----------|----------|
| 存储位置 | 栈内存(值直接存储) | 堆内存(变量存储地址引用) |
| 赋值行为 | 复制值 | 复制引用 |
| 比较方式 | 按值比较 | 按引用比较 |
| 可变性 | 不可变(修改变量实际上是替换值) | 可变(可以修改属性) |
| 类型检测 | typeof 有效 | typeof 返回 "object""function",需其他方法 |

理解这八种类型的本质,是深入掌握后续类型转换、函数传参、深浅拷贝等话题的前提。在下一节中,我们将详细探讨如何准确地判断一个值的类型,以及各种类型判断方案的适用场景与陷阱。