JavaScript是按引用传递还是按值传递的语言?
JavaScript是按引用传递还是按值传递的语言?
技术背景
在编程中,参数传递方式分为按值传递(Pass-by-Value)和按引用传递(Pass-by-Reference)。按值传递是指将变量的值复制一份传递给函数,函数内部对该值的修改不会影响到原始变量;按引用传递则是将变量的内存地址传递给函数,函数内部对该地址所指向的值的修改会影响到原始变量。在JavaScript中,对于参数传递方式存在一定的混淆,下面我们来深入探讨。
实现步骤
按值传递示例
1 |
|
在这个例子中,x
是一个原始类型(数字),当将 x
传递给 changePrimitive
函数时,实际上是将 x
的值 10
复制了一份传递给 val
。在函数内部修改 val
的值不会影响到原始的 x
。
按引用传递(实际是按值传递引用)示例
1 |
|
这里 x
是一个对象,当将 x
传递给 changeObject
函数时,传递的是 x
的引用的副本。函数内部通过这个引用副本修改了对象的属性,所以原始的 x
对象也受到了影响。
重新赋值引用示例
1 |
|
在这个例子中,虽然传递的是对象的引用副本,但在函数内部将 obj
重新赋值为一个新的对象,这只是改变了 obj
这个局部变量所指向的对象,不会影响到原始的 x
对象。
核心代码
原始类型按值传递
1 |
|
对象类型按值传递引用
1 |
|
重新赋值对象引用
1 |
|
最佳实践
避免混淆
要明确JavaScript中所有参数传递都是按值传递,对于对象传递的是引用的副本。在编写代码时,要清楚函数内部对参数的操作是修改对象属性还是重新赋值引用。
传递对象副本
如果需要传递对象的副本而不是引用,可以手动复制对象,例如使用扩展运算符 ...
:
1 |
|
这样在函数内部对 obj
的修改不会影响到原始的 obj
。
常见问题
为什么对象传递看起来像按引用传递?
因为传递对象时,传递的是引用的副本,函数内部可以通过这个引用副本修改对象的属性,从而影响到原始对象,所以看起来像按引用传递。但实际上如果在函数内部重新赋值引用,不会影响到原始对象,这证明还是按值传递。
如何判断是按值传递还是按引用传递?
如果函数内部对参数的修改不会影响到原始变量,就是按值传递;如果能通过参数修改原始变量所指向的值,就是按引用传递。但在JavaScript中,原始类型是按值传递,对象是按值传递引用。