JavaScript原始类型传参是值传递,实参值被完整复制到函数栈帧新空间,与外部变量物理隔离;字符串、数字等不可变,所有“修改”实为创建新值,不影响原始变量。
JavaScript 中原始类型在参数传递时,内存表现非常直接:实参的值被完整复制一份,存入函数调用栈帧的新空间里,和外部变量物理隔离。
原始类型(number、string、boolean、null、undefined、symbol、bigint)的值直接存于栈内存。传参时,JS 在当前函数的栈帧中为形参分配一块新空间,并把实参的值原样拷贝过去——不是地址,不是引用,就是数据本身。
let a = "hello",传入函数后,形参 str 拥有自己的一份 "hello" 字符串副本,两者在栈中是两块不同的内存单元a 和 str 内容相同,它们的内存地址不同,修改其中一个对另一个毫无影响因为字符串不可变、数字不可变,所有看似“修改”的操作(如 n += 1、s.toUpperCase())实际都是创建新值并赋给局部变量,原始变量所在栈位置的数据纹丝不动。
function f(x) { x = x + 1; } → 只改了形参 x 所在栈位置的值function g(s) { s = s.replace('a', 'b'); } → s 指向一个新字符串,旧字符串仍由外部变量持有function h(a) { a = 99; },也只重写函数栈帧里的那个 a
对象传参也是按值传递,但那个“值”是堆内存地址;原始类型传的“值”,是栈里实实在在的数据。这导致行为差异的根本原因不在“传参方式”,而在“所传之值的性质”。
立即学习“Java免费学习笔记(深入)”;
{x: 1}:形参拿到的是地址副本,通过它读写属性,会反映到同一块堆内存上42:形参拿到的是数字 42 的副本,再怎么算,外部的 42 还在原来栈位置安好无损param = ...)一定不影响;操作参数属性或元素(param.prop = ...)才可能影响——但原始类型根本没有属性可操作栈内独立存储让原始类型天然具备纯函数友好性:参数不可被意外篡改,副作用可控,逻辑可预测。