-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: