一文吃透 JavaScript 八大数据类型 + 内存存储原理(附实战代码)
前言
学习 JavaScript 绕不开数据类型 和内存存储机制 ,这也是前端基础面试高频考点。很多同学分不清 null 和 undefined、搞不懂原始值与对象的赋值区别、疑惑小数精度丢失、大整数溢出等问题。
本文结合实战代码 + 内存原理 + 场景解析,完整梳理 JS 8 大数据类型、栈 / 堆内存分配、赋值机制、常见坑点,适合日常复习与查漏补缺。
一、JS 总共有多少种数据类型?
按照 ECMA-262 规范,目前 JavaScript 一共分为 8 种数据类型 ,整体划分为 ** 原始数据类型(基本类型)和 引用数据类型(复杂类型)** 两大类。 
1. 原始数据类型(Primitive 基本类型)
共 7 种 ,ES6 之后新增 Symbol 和 BigInt:
number数值类型string字符串类型boolean布尔类型null空值类型undefined未定义类型Symbol符号类型(ES6 新增)BigInt大整数类型(ES6+ 新增)
2. 引用数据类型(复杂类型)
仅 1 种:
object对象类型细分:普通对象{}、数组[]、函数、正则、日期等,本质都属于object。
补充:ES6 之前 JS 只有 6 种数据类型 (无
Symbol、BigInt)。
二、内存底层:栈内存 & 堆内存(核心重点)
理解数据类型,必先搞懂 JS 内存划分,这也是赋值差异的根本原因。
1. 两大内存区域特点
计算机运行代码时,代码从硬盘(外存)加载到内存,内存主要分为栈内存 和堆内存:
表格
| 内存区域 | 特点 | 存储内容 |
|---|---|---|
| 栈内存(Stack) | 空间小、速度快、结构固定、自动回收 | 原始数据类型的值、引用类型的内存地址函数执行上下文也存放在栈中 |
| 堆内存(Heap) | 空间大、速度慢、空间不固定、不会自动回收 | 引用类型(对象、数组)的真实数据 |
2. 核心规则
- 原始数据类型 :空间大小固定,直接存放在栈内存中。
- 引用数据类型 :真实数据存放在堆内存 ;栈内存中仅保存堆内存的地址(引用地址) 。
- 函数执行完毕后,栈内存会自动释放;堆内存需要 JS 垃圾回收机制回收,也可手动置空触发回收。
三、赋值机制:原始值拷贝 vs 引用值拷贝(代码实战)
根据内存存储规则,两种数据类型的赋值行为完全不同,也是日常开发最容易踩坑的点。
1. 原始类型:值拷贝(完全独立)
原始类型赋值是复制一份全新的值,两个变量互不干扰,修改其中一个不会影响另一个。
javascript
运行
javascript
// null 属于原始类型
let a = null
let b = a // 栈中拷贝值:b = null
b = 2 // 仅修改 b 栈内的值,和 a 无关
console.log(a) // null
console.log(b) // 2
原理 :a 和 b 在栈内存是两个独立空间,赋值只是把值复制一份,相互隔离。
2. 引用类型:地址拷贝(共用同一堆数据)
对象、数组属于引用类型,赋值时不会拷贝堆里的真实数据 ,只会把栈中的内存地址 拷贝给新变量。多个变量指向堆中同一个数据,任意一个变量修改数据,所有关联变量都会受影响。
javascript
运行
bash
let obj1 = { name: "谢鲁立" }
let obj2 = obj1 // 拷贝堆内存地址,obj1、obj2 指向同一个对象
obj2.company = "快手" // 通过地址修改堆中的真实数据
console.log(obj1, obj2)
// { name: '谢鲁立', company: '快手' } { name: '谢鲁立', company: '快手' }
原理 :obj1、obj2 栈内地址相同,指向堆中同一个对象,一改全改。
四、null 与 undefined 深度解析(高频区分考点)
这两个类型都表示 "空",但语义、使用场景完全不同,下面结合代码逐一说明。
1. null 空值类型
语义
有意设置为空 ,表示此处本该有一个对象引用,但现在主动置空。
- 属于原始类型
- 作用:清空对象引用、手动释放堆内存、标记 "无后续节点 / 数据"
典型使用场景
- 手动释放堆内存,辅助垃圾回收
javascript
运行
javascript
// 超大数组,占用大量堆内存
let largeObject = {
data: new Array(100000000).fill("xll")
}
largeObject = null;
// 栈中地址置空,堆中大数据失去引用,会被垃圾回收
- 标记对象 / 链表无后续节点 经典链表场景:
node.next本应存下一个节点的引用,赋值null代表没有下一个节点。
javascript
运行
ini
node.next = null
- 主动定义 "空对象占位"
javascript
运行
javascript
let obj = {
name: '吴咸鸡',
address: null // 主动设置:地址字段目前为空
}
console.log(obj.address) // null
2. undefined 未定义类型
语义
被动产生的空 ,表示变量 / 属性 / 返回值未初始化、不存在。属于原始类型,出现场景固定,一共 4 种:
场景 1:变量声明,但未赋值
javascript
运行
javascript
let a // 只声明,不赋值
console.log(a) // undefined
场景 2:访问对象不存在的属性
javascript
运行
javascript
let obj = {}
console.log(obj.name) // undefined
场景 3:访问数组不存在的索引
javascript
运行
ini
let arr = [1, 2, 3]
console.log(arr[5]) // undefined
场景 4:函数无 return 返回值
函数没有手动写 return,默认返回 undefined:
javascript
运行
javascript
function notReturn() {
// 无 return
}
console.log(notReturn()) // undefined
总结:null vs undefined
null:人为主动设置的空(空对象引用)。undefined:代码运行时被动生成的空(未初始化、不存在)。
五、Number 数值类型:精度问题 & 大数溢出
JS 所有普通数字都属于 number 类型,底层统一使用二进制存储 ,由此带来两个经典问题:小数精度丢失 、超大整数溢出。
1. 经典坑点:小数运算不精确
二进制无法精准表示部分十进制小数,导致运算结果异常:
javascript
运行
css
let a = 0.1
let b = 0.2
console.log(a + b)
// 输出:0.30000000000000004
原因:0.1、0.2 转二进制是无限循环小数,存储时被截断,造成精度丢失。
2. 超大整数溢出
number 类型有安全整数范围,超出范围会精度失真、科学计数法展示:
javascript
运行
ini
let num1 = 999999999999999999999999999999999999999999999999999999999999999
let num2 = 123456789098765433467324577654789008733233456899003466788924243
console.log(num1 + num2);
// 输出:1.1234567890987655e+63(科学计数法,精度丢失)
六、BigInt 大整数类型(ES6+ 新增)
为解决 number 大数溢出问题,ES 新增 BigInt 类型,专门用来表示任意长度的大整数。
使用规则
- 数字末尾加 n 即为 BigInt 类型;
- BigInt 和 Number 不能直接混合运算,会报错;
- 只能和同类型(BigInt)运算。
javascript
运行
javascript
// 定义 BigInt:数字后加 n
let num3 = 999999999999999999999999999999999999999999999999999999999999999n
let num4 = 123456789098765433467324577654789008733233456899003466788924243n
console.log(num3 + num4, typeof num3);
// 正常运算,typeof 结果为 bigint
// 报错:BigInt 不能和普通 Number 直接运算
// console.log(num3 + 1);
// 正确:统一转为 BigInt
console.log(num3 + 1n)
七、Symbol 符号类型(ES6 新增)
核心特性
- 独一无二 :哪怕描述文本相同,两个
Symbol也绝不相等; - 属于原始数据类型;
- 常用于对象私有属性、唯一标识符。
代码演示
javascript
运行
javascript
// 两个描述相同的 Symbol
console.log(Symbol("xll") === Symbol("xll")) // false
// 检测类型
console.log(typeof Symbol("xll")) // symbol
// Symbol 可以不传参数,代表绝对唯一
console.log(Symbol()) // Symbol()
实际应用:对象唯一键名
利用唯一性,给对象设置不会冲突的属性名:
javascript
运行
csharp
let obj = {
[Symbol("xll")]: "谢鲁立", // Symbol 作为属性名
prop: "1"
}
八、完整知识复盘(复习提纲)
1. 数据类型总览(8 种)
- 原始类型(7 种):
number、string、boolean、null、undefined、Symbol、BigInt - 引用类型(1 种):
object(对象、数组、函数等)
2. 内存存储规则
- 栈内存:存放原始值 、引用类型的地址;空间小、速度快、自动回收。
- 堆内存:存放对象 / 数组真实数据;空间大、速度慢、依赖垃圾回收。
3. 赋值区别
- 原始类型:值拷贝,变量相互独立。
- 引用类型:地址拷贝,多变量指向同一堆数据,一改全改。
4. null & undefined 区分
null:主动置空,空对象引用,可用于释放内存。undefined:被动产生,变量未赋值、属性不存在、函数无返回值。
5. Number / BigInt
number:二进制存储,存在小数精度丢失、大数溢出。BigInt:后缀加n,支持超大整数,不能和普通数字混合运算。
6. Symbol
- 天生唯一,适合做对象私有属性、唯一标识。
结尾
本文把 JS 数据类型、内存原理、赋值机制、常见坑点全部结合代码落地,日常复习可以对照代码逐行理解。这部分是 JS 根基,后续原型、作用域、闭包、深浅拷贝等知识点,都建立在栈 / 堆内存 和数据类型之上。