JavaScript是按引用传递还是按值传递的语言?

JavaScript是按引用传递还是按值传递的语言?

技术背景

在编程中,参数传递方式分为按值传递(Pass-by-Value)和按引用传递(Pass-by-Reference)。按值传递是指将变量的值复制一份传递给函数,函数内部对该值的修改不会影响到原始变量;按引用传递则是将变量的内存地址传递给函数,函数内部对该地址所指向的值的修改会影响到原始变量。在JavaScript中,对于参数传递方式存在一定的混淆,下面我们来深入探讨。

实现步骤

按值传递示例

1
2
3
4
5
6
function changePrimitive(val) {
val = val * 10;
}
var x = 10;
changePrimitive(x);
console.log(x); // 输出: 10

在这个例子中,x 是一个原始类型(数字),当将 x 传递给 changePrimitive 函数时,实际上是将 x 的值 10 复制了一份传递给 val。在函数内部修改 val 的值不会影响到原始的 x

按引用传递(实际是按值传递引用)示例

1
2
3
4
5
6
function changeObject(obj) {
obj.val = obj.val * 10;
}
var x = { val: 10 };
changeObject(x);
console.log(x.val); // 输出: 100

这里 x 是一个对象,当将 x 传递给 changeObject 函数时,传递的是 x 的引用的副本。函数内部通过这个引用副本修改了对象的属性,所以原始的 x 对象也受到了影响。

重新赋值引用示例

1
2
3
4
5
6
function changeObject(obj) {
obj = { val: 100 };
}
var x = { val: 10 };
changeObject(x);
console.log(x.val); // 输出: 10

在这个例子中,虽然传递的是对象的引用副本,但在函数内部将 obj 重新赋值为一个新的对象,这只是改变了 obj 这个局部变量所指向的对象,不会影响到原始的 x 对象。

核心代码

原始类型按值传递

1
2
3
4
5
var a = 3;
var b = a;
a = 4;
console.log(a); // 输出: 4
console.log(b); // 输出: 3

对象类型按值传递引用

1
2
3
4
5
var c = { "name": "john" };
var d = c;
c.name = "doe";
console.log(c); // 输出: { "name": "doe" }
console.log(d); // 输出: { "name": "doe" }

重新赋值对象引用

1
2
3
c = { "name": "jane" };
console.log(c); // 输出: { "name": "jane" }
console.log(d); // 输出: { "name": "doe" }

最佳实践

避免混淆

要明确JavaScript中所有参数传递都是按值传递,对于对象传递的是引用的副本。在编写代码时,要清楚函数内部对参数的操作是修改对象属性还是重新赋值引用。

传递对象副本

如果需要传递对象的副本而不是引用,可以手动复制对象,例如使用扩展运算符 ...

1
2
3
4
5
6
7
8
9
10
function process({...obj}) {
obj.a = 'aa';
console.log(obj);
}
let obj = {
a: 'a_val',
b: 'b_val'
};
process(obj);
console.log(obj);

这样在函数内部对 obj 的修改不会影响到原始的 obj

常见问题

为什么对象传递看起来像按引用传递?

因为传递对象时,传递的是引用的副本,函数内部可以通过这个引用副本修改对象的属性,从而影响到原始对象,所以看起来像按引用传递。但实际上如果在函数内部重新赋值引用,不会影响到原始对象,这证明还是按值传递。

如何判断是按值传递还是按引用传递?

如果函数内部对参数的修改不会影响到原始变量,就是按值传递;如果能通过参数修改原始变量所指向的值,就是按引用传递。但在JavaScript中,原始类型是按值传递,对象是按值传递引用。


JavaScript是按引用传递还是按值传递的语言?
https://119291.xyz/posts/is-javascript-pass-by-reference-or-value/
作者
ww
发布于
2025年5月26日
许可协议