-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
JavaScript 是传值调用还是传引用调用? #32
Comments
写得这么详细,赞一个 |
简单易懂!赞! |
传值调用(Call-ny-value)=> 中间那个单词 |
最后一句话突然点醒梦中人,引用传值其实是copy了对象中的指针,指针其实也是值,所以引用传值是一种copy对象指针的传值调用,可以这样理解吗? |
@chenyin151 是的。对于上文中 changeStuff 函数中的 b,对 b 指向的内存进行操作,就会导致原来的值被改变。而对于 c,因为这份 copy 的指针重新赋值了,所以 c 和 obj2 就没有关系了,所以对 c 指向的内存进行操作,就不会影响其他数据。 |
学习了,谢谢 |
谢谢,好久没看有点忘了。。。。 最后传的还是值,只不过这个值有可能是引用。 |
这就是一个 bug. 神坑 |
参数可以等价于函数block 内定义的局部let变量,就很好理解了。这个let 变量指向了实参对象,当然可以也可指向其他对象啦。 |
太强了 |
这个问题可以通过Dan的心智模型完美解决https://justjavascript.com/learn/08-properties |
1. 例子
先来看两个个来自于 《JavaScript 高级程序设计》P70-P71 的两个例子。
1.1. 基本类型参数传递
书上解释说,JavaScript 参数传递都是按值传参。
所以传递给
addTen
函数的值是20
这个值,所以函数执行结束原始变量count
并不会改变。1.2. 引用类型参数传递
为什么结果是
Nicholas
呢?2. 传值还是传引用?
让我们再将上面两个例子综合为下面的例子:
最终的输出结果是:
所以 JS 到底是传值调用还是传引用调用呢?要弄清楚这个问题,首先我们要明白到底什么是传值调用(Call-by-value)和传引用调用(Call-by-reference)。
2.1. 传值调用(Pass by value)
在传值调用中,传递给函数参数是函数被调用时所传实参的拷贝。在传值调用中实际参数被求值,其值被绑定到函数中对应的变量上(通常是把值复制到新内存区域)。
即
changeStuff
的参数a
b
c
是num1
obj1
obj2
的拷贝。所以无论a
b
c
怎么变化,num1
obj1
obj2
都保持不变。问题就在于
obj1
变了。2.2. 传引用调用(Pass by reference)
在传引用调用调用中,传递给函数的是它的实际参数的隐式引用而不是实参的拷贝。通常函数能够修改这些参数(比如赋值),而且改变对于调用者是可见的。
也就是说
changeStuff
函数内的a
b
c
都分别与num
obj1
obj2
指向同一块内存,但不是其拷贝。函数内对a
b
c
所做的任何修改,都将反映到num
obj1
obj2
上 。问题就在于
num
和obj2
没变。从上面的代码可以看出,JavaScript 中函数参数的传递方式既不是传值,也不是传引用。主要问题出在 JS 的引用类型上面。
JS 引用类型变量的值是一个指针,指向堆内存中的实际对象。
2.3. 传共享调用(Call by sharing)
还有一种求值策略叫做传共享调用(Call-by-sharing/Call by object/Call by object-sharing)。
传共享调用和传引用调用的不同之处是,该求值策略传递给函数的参数是对象的引用的拷贝,即对象变量指针的拷贝。
也就是说,
a
b
c
三个变量的值是num
obj1
obj2
的指针的拷贝。a
b
c
的值分别与num
obj1
obj2
的值指向同一个对象。函数内部可以对a
b
c
进行修改可重新赋值。3 代码分析
接下来让我们再来分析一下代码。
3.1 变量初始化
3.2 调用函数
可以看到,变量
a
的值就是num
值的拷贝,变量b
c
分别是obj1
obj2
的指针的拷贝。函数的参数其实就是函数作用域内部的变量,函数执行完之后就会销毁。
3.3 执行函数体
如图所示,变量
a
的值的改变,并不会影响变量num
。而
b
因为和obj1
是指向同一个对象,所以使用b.item = "changed";
修改对象的值,会造成obj1
的值也随之改变。由于是对
c
重新赋值了,所以修改c
的对象的值,并不会影响到obj2
。4. 结论
从上面的例子可以看出,对于 JS 来说:
传值调用本质上传递的是变量的值的拷贝。
传共享调用本质上是传递对象的指针的拷贝,其指针也是变量的值。所以传共享调用也可以说是传值调用。
所以《JavaScript 高级程序设计》说 JavaScript 参数传递都是按值传参 也是有道理的。
参考
The text was updated successfully, but these errors were encountered: