JavaScript原始类型值直接存栈内存,非地址或引用;赋值传参基于内容拷贝,不可变;生命周期由执行上下文自动管理,无需垃圾回收;栈存储保障高性能,与函数调用天然契合。

JavaScript 中原始类型(number、string、boolean、null、undefined、symbol、bigint)的值本身直接存放在栈内存中,不是存地址,也不是存引用——变量所在的位置,就是值待着的地方。
栈里存的是值,不是指针
声明 let a = 42 时,V8 引擎会在当前函数的栈帧里分配一块固定大小的空间,把数字 42 直接写进去。读取 a,引擎就从那个位置取值;赋值 a = 100,就是用新值覆盖旧值。整个过程不涉及堆,也不生成任何引用。
- 字符串哪怕长达上万字符,行为上仍是“按值存储”:赋值、传参、比较都基于内容,而非内存位置
- 你不能通过 str[0] = 'x' 修改字符串首字符,这不是栈限制,而是语言规范强制的不可变语义
- 每次 let b = a 都是复制数值,b 和 a 各自独占一份内存,互不影响
生命周期由执行上下文自动管理
栈内存和函数调用紧密绑定。函数开始执行,它的局部变量(含所有原始类型)被压入栈;函数返回,整块栈帧自动弹出,所有变量立即释放——不需要垃圾回收器介入。
- 原始值不会意外滞留,也不会因闭包而逃逸到堆(除非被长期引用,引擎会自动提升,但对外仍表现为值语义)
- const 对原始类型的作用是锁定变量绑定,防止重新赋值,但它不改变存储位置或内存行为
为什么不用堆来存原始值?
堆适合管理生命周期不确定、体积可能很大、结构复杂的对象。原始类型体积小、长度固定(如 number 总是 64 位浮点)、使用频繁——放在栈里能实现极快的读写速度,且与函数调用栈天然契合。
立即学习“Java免费学习笔记(深入)”;
- 系统栈本身用于维护执行流(如 call stack),把轻量数据也放这里,整体开销低
- 如果把对象也硬塞进栈,每次函数调用/返回都要复制大量数据,栈空间容易溢出,上下文切换成本剧增
- 原始类型存栈、对象存堆,这种分工让引擎能在性能和内存灵活性之间取得平衡
注意几个常见误解
原始类型全部驻留在栈中,没有例外。所谓“string 存堆”“symbol 存注册表”,是指引擎底层可能做优化(如长字符串底层字符数据放堆、Symbol 全局注册表在堆),但对 JS 开发者而言,它们的行为始终是栈语义:
- 赋值拷贝的是值,不是地址
- 比较用 === 是按值判断,不是看是否同一块内存
- 不可变性是语言规范要求,不是内存布局导致的结果


















