js中参数传递方式

一般编程语言中参数传递存在两种方式:按值传递,引用传递。但在Js中,参数的传递有点另类。先看一下值传递和引用传递的概念。

值传递:

形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

引用传递:

形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

另外c++中还有指针传递:形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。引用和指针是两个概念。引用仅是一个别名,具有很多限制;而指针是一个存放对象地址的变量,比较灵活。

js中函数的传参方式

首先,Js的基本类型,是按值传递的。

1
2
3
4
5
6
let a = 1;
function foo(a){
a = 2;
}
foo(a);
console.log(a);//1

这个例子中,function内新定义了一个变量a,并赋值2,这不会影响外部的a。事实上foo(a)可以看出foo(2)。

Js中引用类型传递:

1
2
3
4
5
6
7
8
let a = {
num : 1
}
function foo(obj){
obj.num = 2;
}
foo(a);
console.log(a.num); // 2

a.num 变成了2,看似a的引用传递到函数内。但事实上,并没有。函数内新定义了一个obj,并把{num:1}赋值给了obj,虽然对obj操作会影响到a,但这只是因为他们指向了同一个堆内存中的变量。

1
2
3
4
5
6
7
8
9
10
a------->[堆内存]<-------obj

let a = {
num : 1
}
function foo(obj){
obj = 2;
}
foo(a);
console.log(a); // { num : 1}

当对obj进行赋值操作,a并不会改变。obj并不是a的引用。

《js高级程序设计》上是这样叙述参数传递的:所有函数的参数都是按值传递的,也就是说把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。