1.基本数据类型:
字符串(String)、数字(Number)、布尔(Boolean)、未定义(undefined)、空(null)、BigInt(任意精度的整数)、Symbol(其实例是唯一且不可变的数据类型)
2.引用数据类型:
对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
3.存储区别
|
内存区域 |
特点 |
存储内容 |
|
栈内存 |
容量小、访问速度快、自动分配/释放(函数执行完自动清空)、存储有序 |
基本数据类型、引用数据类型的地址 |
|
堆内存 |
容量大、访问速度稍慢、手动管理(靠垃圾回收机制)、存储无序 |
引用数据类型的实际数据 |
// 1. 基本类型存储:栈内存直接存值
let a = 10;
let b = a; // 复制栈中的值,a和b是两个独立的变量
b = 20; // 修改b的栈值,不影响a
console.log(a); // 输出:10(a的栈值未变)
console.log(b); // 输出:20(b的栈值被修改)
// 2. 不可变性验证:栈中的值无法直接修改,只能重新赋值
let str = "hello";
str[0] = "H"; // 尝试修改栈中的字符串值
console.log(str); // 输出:hello(栈值未变,实际创建了新字符串但未赋值)
// 1. 引用类型存储:栈存地址,堆存数据
let obj1 = { name: "张三" };
let obj2 = obj1; // 复制栈中的地址,obj1和obj2指向同一个堆内存地址
obj2.name = "李四"; // 通过地址修改堆中的数据
console.log(obj1.name); // 输出:李四(堆数据被修改,obj1指向同一地址)
console.log(obj2.name); // 输出:李四
// 2. 地址对比验证:两个看似相同的对象,地址不同
let arr1 = [1,2];
let arr2 = [1,2];
console.log(arr1 === arr2); // 输出:false(栈中的地址不同,堆中数据即使相同也不相等)
// 3. 手动切断引用:重新赋值栈地址,指向新的堆内存
obj1 = { name: "王五" }; // 栈地址改为指向新的堆内存
console.log(obj1.name); // 输出:王五(新堆数据)
console.log(obj2.name); // 输出:李四(旧堆数据,不受影响)
特殊情况:Null的存储
- null是基本类型,但typeof null 返回“object”(JS历史设计bug);
- 存储规则:栈存储中直接存储null值(而非地址),本质仍是基本类型的存储方式;
- 示例:
-
let n = null; let m = n; m = 10; console.log(n)//输出:null(栈值独立,符合基本类型特征)延伸:函数传参的存储影响
函数传参的本质是“变量赋值”,存储方式直接影响传参效果:
-
// 1. 基本类型传参:传值(复制栈值),函数内修改不影响外部 function changeNum(num) { num = 100; } let x = 10; changeNum(x); console.log(x); // 输出:10 // 2. 引用类型传参:传地址(复制栈地址),函数内修改堆数据影响外部 function changeObj(obj) { obj.name = "李四"; } let person = { name: "张三" }; changeObj(person); console.log(person.name); // 输出:李四 // 3. 函数内重新赋值地址:切断引用,不影响外部 function resetObj(obj) { obj = { name: "王五" }; // 栈地址指向新堆内存,和外部变量无关 } resetObj(person); console.log(person.name); // 输出:李四(外部地址未变)总结:存储区别的核心影响
影响维度
基本类型
引用类型
赋值/传参
复制值(独立),修改互不影响
复制地址(共享),修改堆数据互相影响
比较规则
比较栈中的值是否相等
比较栈中的地址是否相等
可变性
栈值不可改,只能重新赋值
堆数据可动态修改(地址不变)
垃圾回收
函数执行完栈值自动释放
无引用指向地址时,堆数据被回收

998

被折叠的 条评论
为什么被折叠?



