JavaScript 数据存储机制:栈与堆的奥秘
一、JavaScript 的数据类型
JavaScript 的数据类型分为两大类:
原始类型(基本类型)
ini
let str = 'hello'; // 1. string
let num = 123; // 2. number
let flag = true; // 3. boolean
let nu = null; // 4. null
let un; // 5. undefined (未定义)
let sy = Symbol('hello'); // 6. symbol (唯一值)
let bi = BigInt(123); // 7. bigint (大整数)
引用类型(复杂类型)
javascript
let obj = { name: '梅老板' }; // 1. Object
let arr = [1, 2, 3]; // 2. Array
function fn() {} // 3. Function
let date = new Date(); // 4. Date
二、JavaScript 语言特性
-
动态语言:变量类型在运行时确定
inilet dynamicVar = 10; // 数字类型 dynamicVar = 'hello'; // 变为字符串类型
-
弱类型:支持隐式类型转换
arduinoconsole.log(10 + '10'); // "1010" (数字转字符串) console.log(10 - '5'); // 5 (字符串转数字)
三、内存空间结构
JavaScript 引擎管理的内存空间分为三个区域:
- 代码空间:存储可执行代码
- 栈空间:存储原始类型值和引用地址
- 堆空间:存储引用类型实际数据
栈空间的特点:
- 存储原始类型值
- 存储引用类型的地址指针
- 空间小,访问速度快
- 自动分配和释放
堆空间的特点:
- 存储引用类型实际数据
- 空间大,访问速度相对较慢
- 需要垃圾回收机制管理
四、数据存储机制
1. 原始类型的存储(栈空间)
ini
function demo() {
let a = 1; // 在栈中创建值 1
let b = a; // 在栈中创建值 1 的副本
a = 2; // 修改栈中的 a 值
console.log(a); // 2
console.log(b); // 1 (b 保持原值)
}
demo();
2. 引用类型的存储(堆空间)
ini
function demo() {
let obj1 = { name: '成哥' }; // 1. 在堆中创建对象
// 2. 栈中存储指向堆的地址
let obj2 = obj1; // 复制栈中的地址
obj1.name = '周圣'; // 修改堆中对象
console.log(obj1); // { name: '周圣' }
console.log(obj2); // { name: '周圣' } (共享同一对象)
}
demo();
五、关键概念解析
1. 按值传递 vs 按引用传递
JavaScript 中所有函数参数都是按值传递:
- 原始类型:传递值的副本
- 引用类型:传递地址的副本
ini
function modify(obj) {
obj.name = '修改后的值'; // 修改原对象
obj = { value: 100 }; // 创建新对象(不影响原变量)
}
let myObj = { name: '原始值' };
modify(myObj);
console.log(myObj.name); // "修改后的值"
2. 经典示例分析
ini
function foo(person) {
person.age = 20; // 修改原对象的属性
person = { // 给参数重新赋值新对象
name: '刘洋' // (不影响外部变量)
};
return person;
}
let p1 = { name: '张三', age: 18 };
let p2 = foo(p1);
console.log(p1); // {name: '张三', age: 20}
console.log(p2); // {name: '刘洋'}
执行过程解析:
p1
传入函数时,复制其地址到person
参数person.age = 20
修改堆中原对象person = {...}
使参数指向新对象- 返回的新对象赋值给
p2
六、特殊类型注意事项
1. Symbol 的唯一性
ini
let s1 = Symbol('key');
let s2 = Symbol('key');
console.log(s1 === s2); // false (每个Symbol都是唯一的)
2. BigInt 的使用
arduino
const bigNumber = 9007199254740991n; // 超过Number安全整数范围
console.log(bigNumber + 1n); // 9007199254740992n
3. typeof 检测的特别情况
javascript
console.log(typeof null); // "object" (历史遗留问题)
console.log(typeof function(){}); // "function"
七、总结
JavaScript 的数据存储机制遵循以下核心原则:
- 原始类型:值直接存储在栈空间,赋值时创建值副本
- 引用类型:数据存储在堆空间,栈中存储指向堆的地址指针
- 参数传递:始终按值传递(原始值或地址值的副本)
- 动态特性:变量类型在运行时确定,可自由转换
- 内存管理:栈空间自动释放,堆空间由垃圾回收机制管理