JavaScript函数参数到底是按值传递还是引用传递?
发布日期:2021-05-20 10:07:09 浏览次数:42 分类:技术文章

本文共 2456 字,大约阅读时间需要 8 分钟。

1、传递参数

ECMAScript 中所有函数的参数都是按值传递的。这意味着函数外的值会被复制到函数内部的参数

中,就像从一个变量复制到另一个变量一样。如果是原始值,那么就跟原始值变量的复制一样,如果是
引用值,那么就跟引用值变量的复制一样。对很多开发者来说,这一块可能会不好理解,毕竟变量有按
值和按引用访问,而传参则只有按值传递
在按值传递参数时,值会被复制到一个局部变量(即一个命名参数,或者用 ECMAScript 的话说,
就是 arguments 对象中的一个槽位)。在按引用传递参数时,值在内存中的位置会被保存在一个局部变
量,这意味着对本地变量的修改会反映到函数外部。(这在 ECMAScript 中是不可能的。)来看下面这个
例子:

```jsfunction addTen(num) {  num += 10;  return num; } let count = 20;
let result = addTen(count); console.log(count); // 20,没有变化console.log(result); // 30

这里,函数 addTen()有一个参数 num,它其实是一个局部变量。在调用时,变量 count 作为参数

传入。count 的值是 20,这个值被复制到参数 num 以便在 addTen()内部使用。在函数内部,参数 num
的值被加上了 10,但这不会影响函数外部的原始变量 count。参数 num 和变量 count 互不干扰,它们
只不过碰巧保存了一样的值。如果 num 是按引用传递的,那么 count 的值也会被修改为 30。这个事实
在使用数值这样的原始值时是非常明显的。但是,如果变量中传递的是对象,就没那么清楚了。比如,
再看这个例子:

function setName(obj) {
obj.name = "Nicholas"; } let person = new Object(); setName(person); console.log(person.name); // "Nicholas"

这一次,我们创建了一个对象并把它保存在变量 person 中。然后,这个对象被传给 setName()

方法,并被复制到参数 obj 中。在函数内部,obj 和 person 都指向同一个对象。结果就是,即使对象
是按值传进函数的,obj 也会通过引用访问对象。当函数内部给 obj 设置了 name 属性时,函数外部的
对象也会反映这个变化,因为 obj 指向的对象保存在全局作用域的堆内存上。很多开发者错误地认为,
当在局部作用域中修改对象而变化反映到全局时,就意味着参数是按引用传递的。为证明对象是按值传
递的,我们再来看看下面这个修改后的例子:

function setName(obj) {
obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } let person = new Object(); setName(person); console.log(person.name); // "Nicholas"

这个例子前后唯一的变化就是 setName()中多了两行代码,将 obj 重新定义为一个有着不同 name

的新对象。当 person 传入 setName()时,其 name 属性被设置为"Nicholas"。然后变量 obj 被设置
为一个新对象且 name 属性被设置为"Greg"。如果 person 是按引用传递的,那么 person 应该自动将
指针改为指向 name 为"Greg"的对象。可是,当我们再次访问 person.name 时,它的值是"Nicholas",
这表明函数中参数的值改变之后,原始的引用仍然没变。当 obj 在函数内部被重写时,它变成了一个指
向本地对象的指针。而那个本地对象在函数执行结束时就被销毁了
注意 ECMAScript 中函数的参数就是局部变量。

摘自《你不知道的JavaScript》


下面是例子

例子引用他人文章,这里我做个抛砖引玉之人,这个问题的确不是很好理解。

1、

function test(m) {
m = {
v : 5}; } var m = {
k : 30}; test(m); alert(m.v); // undefined

在这里插入图片描述

2、

var obj = {
value: 1};function foo(o) {
o.value = 2; console.log(o.value); //2}foo(obj);console.log(obj.value) // 2

3、

var obj = {
value: 1};function foo(o) {
o = 2; console.log(o); //2}foo(obj);console.log(obj.value) // 1

如果 JavaScript 采用的是引用传递,外层的值也会被修改呐,这怎么又没被改呢?所以真的不是引用传递吗?

这就要讲到其实还有第三种传递方式,叫按共享传递。

而共享传递是指,在传递对象的时候,传递对象的引用的副本。

注意: 按引用传递是传递对象的引用,而按共享传递是传递对象的引用的副本!

所以修改 o.value,可以通过引用找到原值,但是直接修改 o,并不会修改原值。所以第二个和第三个例子其实都是按共享传递。

最后,你可以这样理解:

参数如果是基本类型是按值传递,如果是引用类型按共享传递。

但是因为拷贝副本也是一种值的拷贝,所以在高程中也直接认为是按值传递了。

所以,高程,谁叫你是红宝书嘞!

里面有很多讨论,建议还是看原文
附上

转载地址:https://blog.csdn.net/weixin_45416217/article/details/115530715 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:记一次if else 日常开发的简单优化写法
下一篇:ant-design-mobile-Tabs纵向滑动触发切换tab问题解决方式

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月10日 08时42分44秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章