JavaScript 有哪几种数据类型?请简要描述每种数据类型的特点。

25 阅读4分钟

JavaScript 有哪几种数据类型?请简要描述每种数据类型的特点。

核心答案

JavaScript 共有 8 种数据类型,分为两大类:

原始类型(Primitive)— 7 种:

类型特点
Number双精度 64 位浮点数(IEEE 754),包含整数、浮点数、InfinityNaN
String不可变的 UTF-16 编码字符序列
Boolean只有 truefalse 两个值
Undefined变量已声明但未赋值的默认值,全局只有一个值 undefined
Null表示"空值"或"无对象",全局只有一个值 null
SymbolES6 引入,每个 Symbol 值都是唯一且不可变的,用作对象属性的唯一标识符
BigIntES2020 引入,可以表示任意精度的整数,突破 Number 的安全整数限制

引用类型(Reference)— 1 种:

类型特点
Object键值对的集合,Array、Function、Date、RegExp、Map、Set 等都属于 Object

深入解析

存储机制的本质区别

  • 原始类型:值存储在栈内存中(实际上 V8 引擎中小整数 Smi 直接内嵌在指针中),按值访问,赋值时复制值本身。
  • 引用类型:值存储在堆内存中,栈中存储的是指向堆内存的引用(地址),赋值时复制的是引用。
栈内存                    堆内存
┌──────────────┐         ┌──────────────────┐
│ a = 1        │         │                  │
│ b = "hello"  │         │ { name: "Tom" }  │◄─┐
│ obj ─────────│─────────┤                  │  │
│ obj2 ────────│─────────┘                  │  │
└──────────────┘         └──────────────────┘
  obj 和 obj2 指向同一个堆内存地址

各类型的底层细节

Number:采用 IEEE 754 双精度浮点数,这意味着:

  • 安全整数范围:-(2^53 - 1)2^53 - 1
  • 存在精度问题:0.1 + 0.2 !== 0.3
  • 特殊值:NaN(唯一一个不等于自身的值)、Infinity-Infinity+0-0

String:不可变(immutable),任何"修改"操作都会创建新字符串。内部使用 UTF-16 编码,一个字符占 2 或 4 字节(代理对)。

Symbol:即使描述相同,每个 Symbol 也是唯一的。Symbol.for() 可以创建全局共享的 Symbol。

BigInt:不能与 Number 混合运算,没有精度上限。

常见误区

  • 误区一typeof null === "object"。这是 JS 历史遗留的 bug(V8 底层用低位标记类型,null 的全零标记被误判为对象),但 null 是原始类型。
  • 误区二:认为 "Function 是独立的数据类型"。typeof function(){} 返回 "function",但 Function 在规范中属于 Object 的子类型,不是独立的数据类型。
  • 误区三:认为 undefined == null 说明它们是一回事。== 相等只是规范的特殊规定,它们语义完全不同:undefined 表示"未定义",null 表示"空值"。

代码示例

// ========== 类型检测 ==========

// typeof 运算符
typeof 42;            // "number"
typeof "hello";       // "string"
typeof true;          // "boolean"
typeof undefined;     // "undefined"
typeof null;          // "object"  ⚠️ 历史 bug
typeof Symbol();      // "symbol"
typeof 42n;           // "bigint"
typeof {};            // "object"
typeof [];            // "object"  —— 数组也是对象
typeof function(){};  // "function" —— 特殊返回值,但 Function 本质是 Object

// 更准确的类型检测
Object.prototype.toString.call(null);       // "[object Null]"
Object.prototype.toString.call([]);         // "[object Array]"
Object.prototype.toString.call(new Date()); // "[object Date]"

// ========== 原始类型 vs 引用类型 ==========

// 原始类型:按值复制
let a = 1;
let b = a;
b = 2;
console.log(a); // 1(不受影响)

// 引用类型:按引用复制
let obj1 = { name: "Tom" };
let obj2 = obj1;
obj2.name = "Jerry";
console.log(obj1.name); // "Jerry"(被修改了)

// ========== 各类型特殊行为 ==========

// Number 精度问题
0.1 + 0.2 === 0.3;           // false
0.1 + 0.2;                   // 0.30000000000000004
Number.MAX_SAFE_INTEGER;     // 9007199254740991 (2^53 - 1)

// BigInt
const big = 9007199254740991n + 1n; // 9007199254740992n(精确)
// big + 1;  // ❌ TypeError: Cannot mix BigInt and other types

// Symbol 的唯一性
const s1 = Symbol("id");
const s2 = Symbol("id");
s1 === s2;  // false

// Symbol.for 全局共享
const s3 = Symbol.for("id");
const s4 = Symbol.for("id");
s3 === s4;  // true

// NaN 的特殊性
NaN === NaN;       // false
Number.isNaN(NaN); // true

// +0 和 -0
+0 === -0;              // true
Object.is(+0, -0);      // false
1 / +0;                  // Infinity
1 / -0;                  // -Infinity

面试技巧

面试官可能的追问方向:

  1. "如何准确判断数据类型?"typeof 适用于原始类型(注意 null 的 bug),instanceof 适用于引用类型,Object.prototype.toString.call() 是最准确的通用方案。

  2. "null 和 undefined 的区别?"undefined 是系统级的"未定义",null 是程序级的"空值"。函数无返回值时默认返回 undefined;需要显式表示"没有对象"时用 null

  3. "为什么 0.1 + 0.2 !== 0.3?怎么解决?" → IEEE 754 浮点数精度问题。解决方案:使用 Number.EPSILON 比较、转为整数运算、或使用第三方库(如 decimal.js)。

  4. "Symbol 的实际应用场景?" → 对象的私有属性键、防止属性名冲突、内置 Symbol(Symbol.iteratorSymbol.toPrimitive 等)定义对象行为。

  5. "包装对象是怎么回事?" → 原始类型调用方法时,JS 引擎会临时创建对应的包装对象(NumberStringBoolean),方法执行完毕后立即销毁。

一句话总结

JavaScript 有 7 种原始类型(Number、String、Boolean、Undefined、Null、Symbol、BigInt)和 1 种引用类型(Object),核心区别在于原始类型按值存储不可变,引用类型按引用存储可变。