JS函数传参

首先,函数传参不论是传递基本类型值还是引用类型值,都相当于最基本的赋值语句 x = a

When we pass primitive values into a function, the function copies the values into its parameters. It’s effectively the same as using =.

函数传参-基本类型值

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

上面的传参过程就相当于基本的赋值 x = a,然后 x ++,a 不会随之改变。

如果想要改变基本类型值,需要这样借助引用类型值:

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

函数传参-引用类型值

1
2
3
4
5
6
7
8
9
10
11
function foo(x) {
x.push(4);
console.log(x); // [1, 2, 3, 4]
x = [4,5,6]; // 赋值新数组改变了 x 的引用
x.push(7);
console.log(x); // [4, 5, 6, 7]
}
let a = [1,2,3];
foo(a);
console.log(a); // [1, 2, 3, 4]
// 这段代码相当于 x = a 然后 x.push(4),然后 x = b

观察上面的代码可以看到,a 在 x.push(4) 之后变为 [1,2,3,4] 。 x = [4,5,6] 并不能影响 a 的指向,所以 a 仍然指向 [1,2,3,4]。相当于下面这样(其实就是引用类型的赋值操作):

1
2
3
4
5
6
7
8
9
let a = [1,2,3];
let x = a;
x.push(4);
console.log(x); // [1, 2, 3, 4]
console.log(a); // [1, 2, 3, 4]
x = [4,5,6]; // 这里的重新赋值改变了 x 的指向
x.push(7);
console.log(x); // [4, 5, 6, 7]
console.log(a); // [1, 2, 3, 4]

如果要将 a 的值变为[4,5,6,7],必须更改 x 原本指向的数组,而不是为 x (更改指向)赋值一个新的数组。

1
2
3
4
5
6
7
8
9
function foo(x) {
x.length = 0; // 清空数组 没有赋值新数组所以没有改变 x 的引用,x 和 a 的指向相同
x.push(4,5,6,7);
console.log(x); // [4, 5, 6, 7]
}
let a = [1,2,3];
foo(a);
console.log(a); // [4, 5, 6, 7]
// 这段代码相当于 x = a 然后的操作并未将 x 指向新的引用

如果我们传递一个 a.slice(),那么这个过程就相当于 x = a.slice(),即进行了一次浅拷贝。

1
2
3
4
5
6
7
8
9
function foo(x) {
x[1] = 4;
x[3].name = "JS";
console.log(x); // [1, 4, 3, {name: "JS"}]
}
let a = [1,2,3,{name:"gzl"}];
foo(a.slice());
console.log(a); // [1, 2, 3, {name: "JS"}]
// 这段代码中使用了slice