前言
JavaScript 作为一门动态、弱类型的编程语言,数据存储方式与传统静态语言有很大不同。理解 JS 的数据类型、内存分配机制以及数据存储的底层原理非常重要。本文将围绕"数据类型"、"语言类型特性"以及"内存空间"三个核心点,带你系统梳理 JavaScript 的数据存储原理。
一、JavaScript 的数据类型
1. 原始类型(基本类型)
原始类型是最基本的数据单元,存储在栈内存中,具有不可变性。包括:
- String :字符串,如
"hello"
- Number :数字,包括整数和浮点数,如
42
、3.14
- Boolean :布尔值,
true
或false
- null:表示"无"或"空值"
- undefined:变量声明但未赋值时的默认值
- Symbol:ES6 新增,表示独一无二的值,常用于对象属性的唯一标识
- BigInt:大整数类型,用于处理超出最大安全整数范围的数值
特点:
- 占用空间小,存储在栈内存
- 不可变,赋值或操作时会生成新值
2. 引用类型(复杂类型)
引用类型用于存储复杂的数据结构,存储在堆内存中。包括:
- Object :对象,如
{name: "Hua"}
- Array :数组,如
[1, 2, 3]
- Function:函数本质上也是对象
- Date:日期对象
特点:
- 占用空间大,存储在堆内存
- 变量存储的是指向堆内存的引用(地址)
- 可变性强,修改属性会影响原对象
二、JavaScript 的类型特性
1. 静态语言与动态语言
-
静态语言:在使用前就需要确定变量的类型,编译时类型已知。例如 Java、C++
-
动态语言:在使用时不需要确定变量的类型,运行时根据赋值的变量类型来确定。例如 JavaScript、Python
JS 是动态类型语言,变量的类型在运行时根据赋值自动确定。例如:
javascript
let a = 10; // Number
a = "hello"; // String
a = [1, 2, 3]; // Array
2. 强类型与弱类型
-
强类型语言:不支持隐式类型转换,类型不兼容时会报错
-
弱类型语言:支持隐式类型转换,类型可以自动转换 JS 支持隐式类型转换。例如:
javascript
console.log(1 + "2"); // "12"
console.log("5" - 2); // 3
这种灵活性带来了便利,但也容易引发类型相关的 bug。
三、内存空间与数据存储
1. V8 引擎的内存空间划分
V8 是 Chrome 和 Node.js 使用的 JS 引擎。它在执行 JS 代码时,会划分出三大内存空间:
- 代码空间:存放代码文本本身
- 栈空间:用于存储原始类型变量、函数调用上下文等
- 堆空间:用于存储引用类型数据(对象、数组、函数等)
栈空间(Stack)
- 结构简单,先进后出
- 存储原始类型和执行上下文
- 访问速度快,空间有限
堆空间(Heap)
- 结构复杂,无序
- 存储引用类型数据
- 空间大,访问速度相对慢
2. 原始类型与引用类型的存储方式
- 原始类型:变量直接存储值本身,分配在栈空间
- 引用类型:变量存储的是指向堆内存的地址(引用),实际数据存储在堆空间
示例
javascript
let a = 10; // 原始类型,a 存储 10
let b = {num: 1}; // 引用类型,b 存储堆中对象的地址
let c = b; // c 也指向同一个对象
c.num = 2;
console.log(b.num); // 2
四、实战面试题
看完以上内容,相信你已经对数据类型与其存储方式已经很了解了,让我们来做一道经典的面试题
javascript
function foo(person) {
person.age = 20
person = {
name: '小钟'
}
return person
}
let p1 = {
name: '小华',
age: 18
}
let p2 = foo(p1)
console.log(p1);
console.log(p2);
运行结果
输出为:
css
{ name: '小华', age: 20 }
{ name: '小钟' }

过程详解
-
let p1 = { name: '小华', age: 18 }
这里,
p1
是一个引用类型变量,存储的是对象在堆内存中的地址。 -
let p2 = foo(p1)
调用
foo
时,person
形参获得了p1
的地址副本。此时person
和p1
都指向同一个对象。 -
person.age = 20
通过
person
修改对象的age
属性,由于person
和p1
指向同一个对象,所以p1.age
也变成了 20。 -
person = { name: '小钟' }
这一步,
person
被赋值为一个新对象的地址。此时person
指向新对象,而p1
依然指向原来的对象。两者不再关联。 -
return person
返回的是新对象
{ name: '小钟' }
,赋值给p2
。
五、总结
JavaScript 的数据存储机制是理解 JS 语言的基础。原始类型和引用类型的本质区别在于存储位置和可变性。原始类型存储在栈空间,体积小、不可变;引用类型存储在堆空间,体积大、可变。JS 作为动态、弱类型语言,变量类型可以随时变化,类型之间可以自动转换。