事情总是从一个问题开始
let arr = [1,2,3];
change(arr);
console.log(arr); // 此处结果是???
function change(arr) {
arr = new Array(4,5,6);
arr.push(7);
}
这个问题还是很容易答错的,至少我第一次就错了哈哈
先说说js函数参数传递
- 值传递
function addNum(num) {
num += 10; // 此处的num并非外部的num,只不过是一个同名的临时变量,且被赋予了相同的值
return num;
}
let num = 10;
let result = addNum(num);
console.log(num); // 10
console.log(result); // 20
结果该是预料之中吧,因为num是基本数据类型,当作为函数参数的时候,是将字面量的值复制一份给函数参数。所以在函数执行之后,num本身的值并没有被改变,函数中被改变的值仅仅是一个副本而已。
- 引用传递
function setName(obj) {
obj.name = "圣人无名"; // 此处的obj仍然不是外部的obj,但是它指向的内存地址与外部的obj相同,所以修改它的时候影响了外部对象
}
let obj = new Object();
obj.name = "至人无己";
setName(obj);
console.log(obj.name); // 圣人无名
结果差强人意,web是一个引用类型,当作为函数参数的时候,是将对象的引用,也就是对象的内存地址复制一份给函数参数。所以在函数中修改内部的副本同样会影响函数外面的对象本身。
本质是相同的
所以,至此我们发现,其实函数参数传递的过程是一致的,无论参数是
基本数据类型 还是 引用类型,函数内都会创建一个副本变量,然后接收其值,只不过基本数据类型是字面量值,而引用类型是内存地址而已。
而内存地址的相同导致了不同对象之间的互相影响,这才是参数引用传递的 罪魁祸首!
问题的解析
- 场景一
let arr = [1,2,3];
change(arr);
console.log(arr); // [1,2,3,7]
function change(arr) {
// 此处的arr并不是外部的arr,只不过它们指向同一个内存引用
arr.push(7); // 所以此处改变函数内的arr也同时改变了外部的arr
}
熟悉的配方,熟悉的味道,此情此景与上面的引用传递例子毫无二致,结果也是一致的,就不赘述了。
- 场景二
let arr = [1,2,3];
change(arr);
console.log(arr); // [1,2,3]
function change(arr) {
// 此处的arr仍然不是外部的arr,只不过它们指向同一个内存引用
arr = new Array(4,5,6); // 此时重点来了,内部的arr被赋予了新的内存地址!它现在指向一个新创建的Array对象了,所以不再和外部的arr有一点关系
arr.push(7); // 内部的arr被改变了,但是外部的arr不受影响
}
解释都写在了注释中,关键在于,引用传递时对象之所以会互相影响是因为它们指向相同的内存地址,而此情景中内部的arr所指的内存地址被改变了,所以互相影响的问题也就烟消云散了~
- 即使不用new结果也是相同的
let arr = [1,2,3];
change(arr);
console.log(arr); // [1,2,3]
function change(arr) {
arr = [4,5,6];
arr.push(7);
}