关于函数传参的疑问

函数传参数是传引用,为什么下面这样赋值不起作用?

var a = [1,2,3]
function fn(arr){
  arr = a
}
var b = []
funcArr(b)
b   //  []

当遍历就可以

var a = [1,2,3]

function fn(arr){
  for(var i in a){
      arr[i] = a [i]
  }
}
var b = []
funcArr(b)
b   // [1,2,3]

这意味着我不能改变b?可以直接赋值
var a = [1,2,3]

function fn(){
  b = a
}
var b = []
funcArr(b)
b   // [1,2,3]

但是通过传参数b就不能赋值但是可以改变b的key来改变b

function fn(arr){
  arr.push[1]
}
var b = []
funcArr(b)
b   //  [1]

阅读 2.1k
2 个回答

你搞错了一个概念,就是ECMAScript中所有的函数传参都是按值传递的。
1.对于基本类型,都知道是按值传递的(把值从一个变量复制到另一个变量)。
2.对于引用类型,在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量。来看一个例子:

function setName(obj) {
        obj.name = "Sun";
        obj = new Object();
        obj.name = "Moon";
 }
 var person = new Object();
 setName(person);
 console.log(person.name)    //"Sun"

这个例子最后的打印结果是"Sun",而不是"Moon"。
分析一下:

  新创建的对象作为参数传给setName();此时传的是Object在内存中的一个地址,将这个地址复制给了参数 obj,然后通过obj给Object添加了一个值为"Sun"的name属性,下一行又新建了一个Object,并将其地址赋值给了obj,此时的obj指向的是新的Object,切断了与传进来的对象的联系,并添加了"Moon"的"name"属性。如果person是按引用传递的,那么最后的结果必然是"Moon"。这说明即使在函数内部修改了参数的值,但是原始的引用仍然没变。

了解了参数是按值传递的,现在回到你的问题上,你将b作为参数传给function,然后再function内部重新给参数arr赋值为a,b并没有任何变化,所以还是原来的定义的空的数组。

Java/C#/JavaScript 这些语言里提到的引用,并不是 C++ 里面那个引用的概念,对应于 C++ 中的 const 指针可能更贴近一些,所以它并不能从函数里通过赋值来改变实参的值。

你提到的“遍历可以”,是因为你在函数里改变的不是形参,而是形参所引用的对象的属性。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题