原始类型直接存储在栈内存中,值本身而非地址存于栈帧,赋值和读取均为直接操作,不涉及堆或引用,生命周期随函数调用自动管理,性能高效且符合不可变语义。

原始类型(number、string、boolean、null、undefined、symbol、bigint)在 JavaScript 中直接存于栈内存,不是“放进去”,而是值本身就在那里——栈里存的就是 42、"hello"、true 这些东西,不是地址,也不需要跳转。
栈里存的是值,不是指针
声明 let a = 100 时,V8 引擎会在当前函数的栈帧中分配一块固定大小的空间,把数字 100 直接写进去。后续读取 a,引擎直接从那个内存位置取值;赋值 a = 200,就是用新值覆盖旧值。整个过程不涉及堆,也不生成引用。
- 每个原始变量独占一份内存,let b = a 是复制数值,不是共享地址
- 哪怕字符串长达上万字符,行为上仍是“按值存储”:赋值、传参、比较都基于内容,而非内存位置
- 你不能通过任何 JS 语法修改原始值的内部(比如 str[0] = 'x' 静默失败),这不是栈的限制,而是语言规范强制的不可变语义
生命周期由执行上下文决定
栈内存和函数调用紧密绑定。函数开始执行,它的局部变量(含原始类型)被压入栈;函数返回,整块栈帧自动弹出,所有变量立即释放——不需要垃圾回收器介入。
- 这意味着原始值不会意外“滞留”,也不会因闭包而逃逸到堆(闭包捕获的原始值,若被外层函数长期引用,引擎会将其提升至堆,但对外仍表现为值语义)
- const 对原始类型的作用是锁定变量绑定,防止重新赋值,但它不改变存储位置或内存行为
为什么不用堆来存原始值?
堆适合管理生命周期不确定、体积可能很大、结构复杂的对象。原始类型体积小、长度固定(如 number 总是 64 位浮点)、使用频繁——放在栈里能实现极快的读写速度,且与函数调用栈天然契合。
- 系统栈本身用于维护执行流(如 call stack),把轻量数据也放这里,整体开销低
- 如果把对象也硬塞进栈,每次函数调用/返回都要复制大量数据,栈空间容易溢出,上下文切换成本剧增
- 原始类型存栈,对象存堆,这种分工让引擎能在性能和内存灵活性之间取得平衡
不复杂但容易忽略:你写的每行 let x = ...,只要右边是原始值,它就实实在在躺在栈里,等着被快速读、被干净释放。


















