为什么在函数中改变对象会改变它们在内存中指向的内容,但有时会创建一个新的内存对象?

时间:2013-06-28 19:49:20

标签: javascript

我正在阅读this blog关于如何在函数内部更改对象或数组,内存中指向的值也会改变,就像在函数外部更改一样

var a = [1,2,3],
    b = a;

b[0] = 5;
console.log(a); // [5, 2, 3]

将导致与

相同
var a = [1,2,3],
    b = a;

var arrayFunction = function(arr){
   arr[0] = 10;
};

var arr = arrayFunction(b);

console.log(a, b, arr) // [10, 2, 3], [10, 2, 3], [10, 2, 3];

然而我无法理解的是为什么在函数中重新分配多个数组值不会改变它之外的值:

var a = [1,2,3],
    b = a;

var arrayFunction = function(arr){
   arr = ["a", "b", "c"];
   return arr;
};

var result = arrayFunction(b);
console.log(result) //["a", "b", "c"]
console.log(a, b);  //[1, 2, 3], [1, 2, 3]

为什么这不会像第一个例子那样改变内存中的指向值?

可能更好地写出the JSBIN

上的例子

3 个答案:

答案 0 :(得分:3)

这是因为javascript中的对象不是真正通过引用传递。我已经看到它被称为“通过复制引用传递”或“通过句柄传递” - 这两者都更好地描述了实际发生的事情。

在这个例子中:

var b = [1, 2, 3];
var arrayFunction = function(arr) {
   arr = ["a", "b", "c"];
};
arrayFunction(b);

对象引用本身是按值传递的。您实际上并没有更改b变量的值。但是,您的函数参数(arr)和b变量最初指向同一个对象 - 因此,如果您更改了一个,则可以通过其中任何一个引用该对象并查看更改。

当您重新分配arr以指向其他对象时,b变量仍然指向旧对象,并且不会更改。

答案 1 :(得分:2)

请记住,在函数中,arr不是实际的数组; arr是指向数组的引用。

因此,当您说arr[0]时,您正在检索数组,然后获取或更新其中的项目。

但是当你说arr = ["a","b","c"]时,你正在创建一个新对象(在右侧),然后将arr转换为指向新对象的引用。

答案 2 :(得分:1)

在Javascript中,变量只是指向到数组;因此,如果复制变量,则会得到两个指向同一数组的变量:

var a = [1,2,3];
var b = a;

使用a[0] = 99更改数组的元素将使用两个变量进行观察,因为只有一个数组且ab都指向它。

当您改为编写时

a = [5, 6, 7];

您要将a设置为指向另一个不同的数组。

除非您明确询问,否则Javascript永远不会复制数组(例如,使用b = a.slice())。

实际上,任何值(例如对象)都会发生同样的情况。对于数字和字符串,相同的逻辑也是有效的,但是很难注意到副本和共享同一个对象之间的区别,因为数字和字符串不能更改(“不可变”)。

在C和C ++等其他语言中,变量包含值,而不是指针;因此,在进行分配时,例如将对象从一个变量复制到另一个变量,如果需要指针,则需要明确询问它。