JavaScript原始类型(number、string等)存于栈或寄存器,生命周期由执行上下文决定,不参与垃圾回收,不可变且按值传递,与堆上的包装对象有本质区别。

JavaScript 的原始数据类型(number、string、boolean、null、undefined、symbol、bigint)不存放在堆中,只存在于调用栈(stack)或局部执行上下文的内存空间里,生命周期完全由执行上下文的创建与销毁决定。
原始值没有堆内存分配
原始类型是按值传递、不可变的轻量数据。它们不通过 new 构造,也不生成对象引用,因此 JavaScript 引擎(如 V8)会直接将其存储在栈帧(stack frame)中,或在某些优化场景下内联到寄存器或 CPU 缓存中。例如:
let a = 42; // 数字字面量,直接存于当前函数栈帧 let b = "hello"; // 字符串字面量,通常存于栈;长字符串可能有内部字符数组在堆,但变量本身仍持栈上指针(对开发者透明)
注意:虽然字符串底层可能复用堆上的字符数据(尤其长字符串或模板字面量),但变量 b 本身存储的是指向该数据的轻量描述符(不是传统意义上的“引用”),其生命周期仍绑定于所在作用域。
生命周期由执行上下文控制
原始值的内存存在时间严格对应其所处执行上下文的生命周期:
立即学习“Java免费学习笔记(深入)”;
- 全局声明的原始变量,在全局执行上下文创建时分配,页面卸载或上下文销毁时释放;
- 函数内声明的原始变量,在函数调用时压入栈帧,函数返回后该栈帧弹出,变量自动失效;
- 块级作用域(let/const)中的原始值,在进入块时分配,离开块时立即不可访问(尽管实际内存可能延迟回收,但语义上已结束生命周期)。
不存在手动内存管理,也无需关心“释放”
原始类型没有构造函数、不涉及对象引用计数或标记清除机制。它们不参与垃圾回收(GC)流程——因为根本不在堆上。所谓“回收”,只是栈指针移动或寄存器重用的自然结果。开发者不能、也不应尝试:
- 用 delete 删除原始变量(无效且报错);
- 设置为 null 或 undefined 来“释放内存”(无意义,仅改变值);
- 依赖 WeakRef 或 FinalizationRegistry(这些只对堆对象有效)。
与包装对象的关键区别
容易混淆的是 new Number(42) 这类包装对象——它确实在堆上分配,受 GC 管理,且有独立生命周期。但原始值 42 和包装对象 new Number(42) 是两类东西:
- 42 是原始值,栈中存在,无引用、无 GC;
- new Number(42) 是堆对象,可被引用、可被 GC 回收,但日常应避免使用。
自动装箱(如 "abc".toUpperCase())产生的临时包装对象,仅在表达式求值期间存在,之后立即丢弃,不构成内存负担。










