JavaScript对象赋值运行机制及函数传参行为相关疑问
JS对象赋值与函数传参的内存层面原理
首先纠正一个普遍的认知误区:JS中所有的函数传参都是按值传递,不存在按引用传递的规则。传递对象类型时,传递的“值”是对象在堆内存中的地址的副本,而非原始引用本身,这是你出现预期偏差的核心原因。
第一段代码运行原理
代码如下:
function make(g: any, b: any) { g = b; } let obj = {id: 1}; let obj2 = {id: 2}; make(obj, obj2); console.log(obj); console.log(obj2);
内存层面执行过程:
- 变量声明阶段:堆内存会开辟两块独立空间,分别存储
{id: 1}(记为内存地址A)、{id: 2}(记为内存地址B);栈内存的变量obj存储的值为地址A,obj2存储的值为地址B。 - 调用
make(obj, obj2)阶段:函数执行上下文创建形参变量g、b,二者是完全独立于外部obj、obj2的新栈变量:g被赋值为obj的值:地址A的副本b被赋值为obj2的值:地址B的副本
- 执行
g = b时:仅修改了形参g存储的地址值,从A改为B,全程没有修改外部obj的存储值,也没有修改堆内存中的原有数据。 - 函数执行结束后,形参
g、b随执行上下文销毁,外部obj、obj2的指向没有任何变化,最终打印结果分别为{id: 1}、{id: 2},符合逻辑。
第二段代码运行原理
代码如下:
function make(g: any) { g = {}; } let obj = {id: 1}; make(obj); console.log(obj);
内存层面执行过程:
- 变量声明阶段:堆内存开辟空间存储
{id: 1}(地址A),栈变量obj存储地址A。 - 调用
make(obj)阶段:函数执行上下文创建形参g,赋值为地址A的副本,和外部obj是独立的两个栈变量。 - 执行
g = {}时:堆内存新开辟空间存储空对象(地址C),将形参g的存储值修改为地址C,这个修改完全不影响外部obj的存储值,obj仍然指向地址A。 - 函数执行结束后形参销毁,最终打印
obj结果为{id: 1},和第一段代码的逻辑完全一致,不存在异常。
补充:什么时候修改会影响外部对象?
只有当你没有修改形参存储的地址值,而是直接修改地址指向的堆内存内容时,外部对象才会感知到变化,示例如下:
function make(g: any) { g.id = 3; // 直接修改地址指向的堆内存内容 } let obj = {id: 1}; make(obj); console.log(obj); // 打印结果为 {id: 3}
内容的提问来源于stack exchange,提问作者user15361861
相关产品推荐
相关产品推荐

