JavaScript基本数据类型有哪些:7种原始类型完整清单
深入解析 ECMAScript 规范定义的 7 种基本数据类型(Number、String、Boolean、Undefined、Null、Symbol、BigInt),涵盖内存存储模型、值不可变性、装箱机制、类型精准检测与常见边界陷阱。
在 ECMAScript 最新规范标准中,JavaScript 的数据类型被划分为两大家族:原始类型(Primitive Types,亦称基本数据类型)与引用类型(Reference Types / Object)。其中,基本数据类型共有 7 种:Number(数值)、String(字符串)、Boolean(布尔值)、Undefined(未定义)、Null(空值)、Symbol(独一符号,ES6 引入)以及 BigInt(大整数,ES2020 引入)。本文将提供详尽的语法清单、底层内存模型对比、类型安全检测方案与高频避坑指南。
一、什么是原始类型?核心特征与内存存储机制
在深入 7 种类型之前,必须首先从语言底层厘清“原始类型”之所以被称为原始类型的本质原因。与复杂的引用类型(如 Object、Array、Function)相比,原始类型具备三项不可动摇的底层特征:
- 按值直接存储于栈内存(Stack Memory): 原始值占用的内存空间大小固定,JavaScript 引擎在编译执行期间直接将其字面量存放于调用栈的变量槽中,读写性能极高。
- 具备绝对的“值不可变性”(Immutability): 原始值一旦创建,其在内存中的内容永远无法被修改。任何针对原始值的运算、替换或调用字符串/数值方法,返回的都是一个全新的原始值,绝不会在原地改变原值。
- 按值复制(Copy by Value): 当把一个包含原始值的变量赋值给另一个变量时,引擎会在栈中开辟新的存储单元,完整复制该值的二进制副本。此后两个变量彼此完全独立,互不影响。
我们可以通过一段简单的控制台代码验证原始类型的“不可变性”与“按值复制”:
// 示例 1:证明原始值的不可变性
let greeting = "hello";
greeting[0] = "H"; // 在非严格模式下静默失效,严格模式下抛出 TypeError
console.log(greeting);
// 输出示例: "hello"(原值未受任何影响)
// 示例 2:证明原始值的按值复制
let originalScore = 100;
let copiedScore = originalScore;
copiedScore = 80;
console.log(originalScore); // 输出示例: 100
console.log(copiedScore); // 输出示例: 80(两个栈槽彼此完全解耦)
二、7 种原始数据类型逐一详解与清单
接下来,我们将按照 ECMAScript 规范定义,逐一剖析这 7 种原始类型的定义语法、适用边界与运行特征。
1. Number(数值类型)
JavaScript 不区分整型和浮点型,所有的 Number 统一遵循 IEEE 754 标准的双精度 64 位二进制浮点数(Double Precision 64-bit Binary Format)格式存储。
- 数值范围与安全整数: 能表示的安全整数范围为
[-(2^53 - 1), 2^53 - 1],即Number.MIN_SAFE_INTEGER(-9007199254740991) 至Number.MAX_SAFE_INTEGER(9007199254740991)。超出该范围的整数计算会出现精度溢出。 - 三大特殊数值:
Infinity:正无穷大(如1 / 0)。-Infinity:负无穷大(如-1 / 0)。NaN(Not-a-Number):表示非合法数字运算结果(如"abc" * 2)。注意:NaN === NaN恒为false,判断必须依赖Number.isNaN()。
- 经典精度问题: 因为 IEEE 754 无法精确用二进制表示十进制的某些无限循环小数,导致
0.1 + 0.2 === 0.30000000000000004。在金额计算等高精场景中,应结合Number.EPSILON误差容限或采用专门的高精度算术库。
// 运行环境:Node.js 或 现代浏览器控制台
const price = 19.99;
const hex = 0xFF; // 十六进制表示,值为 255
console.log(typeof price); // 输出示例: "number"
console.log(Number.isNaN("hello" * 3)); // 输出示例: true
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON); // 输出示例: true
2. String(字符串类型)
String 用于表示文本数据。在底层,JavaScript 字符串是由 16 位无符号整数构成的 UTF-16 代码单元(Code Units) 序列。
- 字面量写法: 支持单引号
'...'、双引号"..."以及 ES6 引入的反引号模板字面量`...`。模板字面量支持多行排版和${expression}表达式插值。 - 长度计算限制: 字符串的
.length属性统计的是 UTF-16 代码单元的数量。对于超出基本多语言平面(BMP)的 Emoji 或生僻汉字(由 4 个字节/2 个代码单元组成的代理对),"𠮷".length值为2,需借助Array.from(str).length或[...str].length进行真实字符计数。
const username = "Kuku";
const welcomeText = `欢迎您,${username}!当前系统运行正常。`;
console.log(welcomeText);
// 输出示例: "欢迎您,Kuku!当前系统运行正常。"
console.log([ ..."👨👩👧" ].length); // 字符解构处理多码元字符
3. Boolean(布尔类型)
Boolean 逻辑类型只有两个固定的布尔字面量值:true(真)与 false(假)。它是控制流程判断(如 if、三元表达式、循环语句)的核心基石。
在进行逻辑判断或通过
Boolean(val) 强转时,除了以下 8 个值会被解析为 false 之外,其余所有值(包括空对象 {}、空数组 []、字符串 "0")均被判定为 true:false、0、-0、0n(BigInt零)、""(空字符串)、null、undefined、NaN。
4. Undefined(未定义类型)
Undefined 类型只有一个单一的特殊值:undefined。它代表“缺少值,此处原本应该有值但尚未被定义”。
当满足以下任一场景时,JavaScript 引擎会自动赋予该变量或表达式 undefined:
- 使用
let或var声明了变量,但未对其赋予初始值。 - 访问一个对象上根本不存在的属性键。
- 调用函数时,未传入对应的形参。
- 函数执行体中没有书写
return语句,或直接写了空的return;。
let unassignedVariable;
console.log(unassignedVariable); // 输出示例: undefined
function doNothing() {}
console.log(doNothing()); // 输出示例: undefined
5. Null(空值类型)
Null 类型也只有一个字面量值:null。它在语义上表示“有意识地赋予一个空值,表明此处原本应是指向对象的引用,但现在空无一物”。
- 工程使用规范: 当你想主动释放一个大对象的内存占用,或者清空一个原本存储引用对象的变量时,应显式将其赋值为
null(例如timer = null;)。 - 原型链的根基终点: 在 JavaScript 原型链机制中,顶级构造对象
Object.prototype.__proto__的值正好是null,代表原型链在此处终止搜索。
6. Symbol(独一符号类型,ES6 引入)
Symbol 随着 ECMAScript 2015 (ES6) 规范发布,用于生成全局唯一且绝对不可变的标识符。即使两个 Symbol 的描述文本一模一样,它们在内存中依然是完全独立的实体。
- 严禁使用
new构造: 必须使用Symbol("description")工厂函数生成,直接调用new Symbol()会抛出TypeError。 - 核心价值: 作为对象属性的名(Property Key),可以从根本上杜绝多人协作或引入第三方 SDK 时的属性名命名冲突(Name Clashes);此外,
for...in、Object.keys()默认不会枚举 Symbol 键,能提供优雅的半私有封装效果。 - 全局注册表: 如果希望跨模块共享同一个 Symbol,可以使用
Symbol.for("global_key")登记与查找。
const idA = Symbol("userID");
const idB = Symbol("userID");
console.log(idA === idB); // 输出示例: false(描述符相同,但值绝不相等)
const userRegistry = {
[idA]: "98721_Secret"
};
console.log(userRegistry[idA]); // 输出示例: "98721_Secret"
7. BigInt(大整数类型,ES2020 引入)
在 ES2020 之前,JavaScript 超过 2^53 - 1(9007199254740991)的超长整数计算无法保证精度。常见的雪花算法 ID(Snowflake ID)或金融超大数常常在前端被截断变形。为此,官方推出了 BigInt 原始类型。
- 语法表示: 在任意整数末尾追加字母
n(如9007199254740993n),或者使用构造函数BigInt("9007199254740993")。 - 严格隔离与混算禁止:
BigInt无法直接与普通Number进行加减乘除算术混算(如10n + 5会抛出TypeError: Cannot mix BigInt and other types),必须通过显式转型统一数据类型;此外,Math内置对象的许多方法不支持 BigInt。
const maxSafe = Number.MAX_SAFE_INTEGER;
console.log(maxSafe + 1 === maxSafe + 2);
// 输出示例: true(普通 Number 在超出安全区间后发生精度合并)
const bigSafe = BigInt(maxSafe);
console.log(bigSafe + 1n === bigSafe + 2n);
// 输出示例: false(BigInt 精确保持整数区分)
三、如何精准检测原始数据类型与避坑指南
在实际开发中,精准判定未知数据的类型是写出稳健代码的前提。然而,JavaScript 早期实现遗留的历史缺陷让类型检测充满了隐形陷阱。
1. typeof 运算符的判定规则与核心缺陷
typeof 运算符是检测原始类型最便捷的手段,但存在一个极其著名的历史缺陷:typeof null === "object"。
在 1995 年最初发布的第一版 JavaScript 引擎(C 语言实现)中,内部存储变量值采用了 32 位机器字:
- 其中最低的 1~3 位被用作“类型标签”(Type Tag)。当低 3 位全为
000时,代表该变量是一个对象引用(Object)。 - 而
null在 C 语言层面被表示为全零机器码的空指针(0x00)。 - 因此,当
typeof引擎读取null的内存时,直接读取到了低三位的000标签,误判其为对象并返回了"object"。
typeof null 改为 "null"),但由于这会导致全球现有数以亿计的遗留网站发生崩溃破坏兼容性,该提议最终被否决,作为永久历史特性保留。
2. 工业级通用检测范式
基于上述缺陷,在工程实践中,必须遵循以下标准防范范式:
// 1. 判断 null:直接使用严格恒等操作符(绝对不能依赖 typeof)
const isNull = (val) => val === null;
// 2. 判断 NaN:必须使用 Number.isNaN,不能用全局 isNaN(存在隐式转换缺陷)
const isReallyNaN = (val) => Number.isNaN(val);
// 3. 万能权威类型判断器:借用 Object.prototype.toString
function getAccurateType(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
console.log(getAccurateType(null)); // 输出示例: "null"
console.log(getAccurateType(undefined)); // 输出示例: "undefined"
console.log(getAccurateType(42)); // 输出示例: "number"
console.log(getAccurateType(Symbol())); // 输出示例: "symbol"
console.log(getAccurateType(100n)); // 输出示例: "bigint"
四、深入理解:原始值为什么能调用方法?(自动装箱机制)
初学者常常产生一个深刻的疑问:既然原始类型不是对象,在栈中没有属性表,那为什么 "hello".toUpperCase() 或 (123.456).toFixed(2) 却能正常执行?
答案在于 JavaScript 引擎的自动装箱(Auto-boxing / Primitive Wrapper Objects)机制。当你在一个原始类型(特别是 String、Number、Boolean)上尝试访问属性或调用方法时,引擎在后台会静默执行以下三步动作:
- 临时创建包装对象: 在堆内存中自动创建一个与该原始值对应的内置包装类实例,例如执行
new String("hello")。 - 调用对象原型方法: 在这个临时的包装对象上寻找方法并执行,返回计算结果。
- 立刻销毁包装对象: 方法执行完毕后,该临时对象立即被解引用并销毁,由垃圾回收机制回收。
这也解释了为什么你不能给原始类型挂载自定义属性:挂载的属性其实写入了瞬时创建的临时包装对象中,而在该行语句执行完的瞬间临时对象就被销毁了,再次读取时重新创建临时对象,自然返回 undefined:
let text = "test";
text.customTag = "myTag"; // 临时装箱写入,随后临时包装对象立即被垃圾回收
console.log(text.customTag);
// 输出示例: undefined(重新装箱创建新对象,该对象上无 customTag 属性)
需要注意,null 和 undefined 没有对应的包装类对象,因此尝试在它们身上调用任何属性或方法(如 null.toString())都会立即抛出不可恢复的 TypeError: Cannot read properties of null 致命报错。
五、7 种原始数据类型全景特性速查与总结
为了便于在日常编码、接口对接和代码审查中快速查阅,下表梳理了 7 种原始类型的规范版本、返回值与关键注意事项:
总结而言,熟练掌握 JavaScript 的 7 种原始数据类型 是编写健壮前端与 Node.js 应用程序的基石。在架构设计与日常编码中,牢记原始值的栈内存存储特性、绝对不可变性以及 typeof 判定边界,能帮你从根本上杜绝引用串改、类型隐式转换异常及大数截断等深层故障。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
相关标签:








