JavaScript参数传递
徐徐 抱歉选手

按值传递(call by value)与按引用传递(call by reference)属于计算机学科中的求值策略(Evaluation Strategy),它决定了变量之间、函数调用时实参和形参之间值如何传递。

按值传递(call by value)

这是最常用的求值策略,函数的形参是被调用时所传实参的副本,修改形参的值并不会影响实参。

按引用传递(call by reference)

形参接受实参的隐式引用,而不是副本,这意味着,函数形参的值如果被修改,实参也会被修改,两者指向相同的储存区域。

按共享传递(call by sharing)

也叫按对象传递,按对象共享传递。该求值策略被用于Python、Java、Ruby、JS等多种语言。

对于传递到函数参数的对象类型,如果直接改变了拷贝的引用,那么不会影响原来的对象(这是按值传递的特性);如果是通过拷贝的引用,去进行内部的值的操作,那么就会影响原来的对象(这是按引用传递的特性)。

1
2
3
4
5
6
7
8
9
10
11
12
function changeStuff(state1, state2)
{
state1.item = 'changed';
state2 = {item: "changed"};
}

var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

changeStuff(obj1, obj2);
console.log(obj1.item); // obj1.item becomes 'changed'
console.log(obj2.item); // obj2.item is still 'unchanged'

JavaScript值的传递方式

原始类型Primitive如Boolean/String/Number/Undefined/Symbol/BigInt,是按照值传递。

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

虽然foo中传入a且在函数内部a被修改,但修改的是a的副本,外部的a值并没有被影响。

复杂类型Object对象,是按照共享传递的。在实际调用函数传递参数是,函数接受的是对象实参引用的副本。

1
2
3
4
5
6
var obj = {x : 1};
function foo(o) {
o.x = 3;
}
foo(obj);
console.log(obj.x); // 3

函数内部对传入对象的内部进行了值的操作,此时呈现出“按引用传递”的特性。

1
2
3
4
5
6
var obj = {x : 1};
function foo(o) {
o = 100;
}
foo(obj);
console.log(obj.x); // 1

函数内部对传入对象的整体进行了值的操作,此时呈现“按值传递”的特性。

可变与不可变

对象是可变的mutable,因此修改对象本身会影响到共享这个独享的引用和引用副本。

基本类型是不可变的immutable,按共享传递和按值传递没有任何区别,因此JavaScript基本类型符合按值传递和按共享传递。

由于基本类型都是不可变的,我们在JavaScript中对string进行操作,尝试“修改”字符串的内容,以为这样字符串就和原来不一样了。实际上,每一次在字符串上应用方法,返回的都是一个新的字符串,原来的字符串根本没变。

1
2
3
4
5
6
> str = "abc";
< "abc"
> str.replace("a", 11)
< "11bc" // 返回的新的字符串
> str
< "abc" // 原来的字符串根本没变

对象是可变的,指向同一个对象的两个变量都可以修改同一个对象,它们共享同一个对象的引用,通过某一个变量修改对象的内容对另一个变量也有影响。但是某一个变量的指向更改后,并不会影响共享的对象。

1
2
3
4
5
6
7
var obj = {x : 0};
obj.x = 100;
var o = obj;
o.x = 1;
obj.x; // 1, 被修改
o = true;
obj.x; // 1, 不会因o = true改变

参考

JS基础之传参(值传递、对象传递)

  • 本文标题:JavaScript参数传递
  • 本文作者:徐徐
  • 创建时间:2021-04-04 20:10:06
  • 本文链接:https://machacroissant.github.io/2021/04/04/js-func-parameter/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论