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

Why do objects changed in function change what they point to in memory, but sometimes create a new memory object?

本文关键字:内存 对象 改变 创建 一个 函数 为什么      更新时间:2023-09-26

我在这个博客上读到,如果一个对象或数组在函数内部发生了更改,那么所指向的内存中的值也会发生更改,就像在函数外部发生更改一样。

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]

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

在JSBIN 上写出示例可能会更好

这是因为javascript中的对象并不是通过引用传递的。我看到它被称为"通过复制引用传递"或"通过句柄传递"——这两种方法都能更好地描述实际发生的事情。

在本例中:

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

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

但是,当将arr重新指定为指向其他对象时,b变量仍然指向旧对象,并且不会更改。

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

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

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

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

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

使用两个变量都可以观察到用a[0] = 99改变数组的元素,因为只有一个数组,并且ab都指向它

当你写

a = [5, 6, 7];

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

Javascript从不复制数组,除非您明确要求它(例如使用b = a.slice())。

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

在C和C++等其他语言中,变量包含值,而不是指针;因此,当进行赋值时,例如,对象从一个变量复制到另一个变量,如果你想要一个指针,你必须明确要求它