JavaScript函数内对象赋值对全局对象值的影响解析
问题原因解析
核心原因是JavaScript的参数传递规则、变量与对象的引用绑定逻辑,和函数作用域的变量隔离特性共同导致的结果,我们逐行拆解逻辑:
示例代码
let obj1 = { value: "a" } let obj2 = { value: "b" } function change(obj1, obj2) { obj1 = obj2 obj1.value = "c" } change(obj1, obj2); console.log("obj1: ", obj1, "obj2: ",obj2); // 输出:obj1: { value: 'a' } obj2: { value: 'c' }
核心逻辑拆解
- 首先明确基础规则:JavaScript中对象类型的值存储在堆内存中,变量本身保存的是指向堆内存对象的引用地址;函数参数是按共享传递的——也就是函数入参拿到的是实参引用地址的副本,函数内部的参数变量属于函数作用域,和外层同名变量是完全独立的两个变量。
- 调用
change(obj1, obj2)的初始阶段:- 全局
obj1保存指向{value: "a"}对象的地址,全局obj2保存指向{value: "b"}对象的地址 - 函数内部生成两个局部变量
obj1、obj2,分别复制全局两个变量保存的地址:局部obj1初始指向{value:"a"},局部obj2初始指向{value:"b"}
- 全局
- 执行函数内第一行
obj1 = obj2:
这行操作只修改函数内部局部obj1保存的地址,把局部obj2持有的地址赋值给它。执行完成后,局部obj1不再指向最初的{value:"a"}对象,转而和局部obj2、全局obj2指向同一个{value:"b"}对象。这步操作完全不会改动全局作用域的obj1,全局obj1始终持有最初指向{value:"a"}的地址。 - 执行函数内第二行
obj1.value = "c":
这行是给局部obj1当前指向的对象修改属性,由于此时局部obj1指向的就是全局obj2对应的那个对象,修改后这个对象的value属性直接变为"c",所有指向这个对象的变量访问属性时都会拿到新值。
最终结果说明
- 全局
obj1从未被修改过指向,它绑定的{value:"a"}对象也从未被改动过属性,所以最终值保持初始的"a" - 全局
obj2绑定的对象在函数执行时被修改了value属性,所以最终值为"c"
容易混淆的点:如果删掉函数内的
obj1 = obj2语句,直接执行obj1.value = "c",此时局部obj1还指向全局obj1绑定的{value:"a"}对象,修改属性后全局obj1的value也会变成"c"。本质区别是:给变量重新赋值(修改变量保存的引用地址)只会影响当前作用域的变量;而通过引用修改对象本身的属性,所有指向这个对象的变量都会感知到变化。
内容的提问来源于stack exchange,提问作者ljmccode
相关产品推荐
相关产品推荐

