为什么将一个包含数组的变量推入另一个变量,然后更新第一个变量也会更新后者?[复制]

Why pushing a variable containing an array inside another variable, then updating the first also updates the latter? [duplicate]

提问人:Guilherme Pinheiro 提问时间:4/21/2022 最后编辑:MushroomatorGuilherme Pinheiro 更新时间:4/21/2022 访问量:745

问:

我正在学习JS,却遇到了一个意想不到的行为。这可能与局部与全局范围有关,但是我找不到答案。这是怎么回事:

我有两个数组,一个是空的,另一个是带有一些值的。如果将值推入空值的数组,然后使用方法更新值,它也将更新另一个数组中的数组:.push()

let newArr = [];
let valueArr = [0,0];

newArr.push(valueArr); 
// newArr = [[0,0]]
console.log(newArr);

valueArr.push(0); 
// newArr = [0,0,0] --> updates it
console.log(valueArr);

但是,如果现在尝试使用赋值更新变量,它不会更改内部的数组=newArr

let newArr = [];
let valueArr = [0,0];

newArr.push(valueArr); 
// newArr = [[0,0]]
console.log(newArr);

valueArr = [0,0,0]; 
// newArr = [[0,0]] --> does not update it
console.log(newArr);

有谁知道为什么推送有这种行为而重新分配没有?这是由于局部/全局范围,还是当我重新分配变量时,变量失去了踪迹?valueArrnewArr

JavaScript 数组变量

评论

2赞 4/21/2022
valueArr.push(0);推送到现有数组,丢弃先前的引用,并使引用成为全新的数组。valueArr = [0,0,0];valueArr
1赞 Pointy 4/21/2022
该问题与范围无关。当您重新赋值变量值时,以前的值将消失。=

答:

1赞 David Sainez 4/21/2022 #1

顶级域名

如果要更新,请明确执行以下操作:newArr

valueArr = [0,0,0]; 
newArr[0] = valueArr;

深度解释

您需要区分对象和对对象引用。对象是一个“事物”。但是对对象的引用只是描述您正在谈论的“事物”的一种方式。

变量是一种使用名称显式引用对象的方法。但是,您也可以以其他方式引用对象,例如(如您发现的)通过数组索引。

需要明确以下几点:

  1. assignment() 运算符显式创建对对象的引用。稍后可以通过变量名称引用该对象。=
  2. 变量可以随时间推移引用不同的对象(通过重复应用赋值运算符)。
  3. 数组是 JavaScript 对象。每次在赋值运算符的右侧使用方括号 () 时,都会创建一个新的数组对象。[ ]
  4. a.push(b) 隐式创建从某个索引到该时间点被引用的对象的引用。ab
  5. 您可以使用严格的 equality() 运算符来确定两个表达式是否引用同一个对象。===

/* 
We create a new array, lets call it Object 1.
We can refer to that array using the variable name `a`.
*/
let a = [];
/*
We create a new array, lets call it Object 2.
We refer to that array using the variable name `b`.
*/
let b = [0];
/*
When we call `push` we are implicitly creating a 
new reference: from a[0] to Object 2.
*/
a.push(b);
/*
`a[0]` and `b` are both referring to
the *exact same* object: Object 2.
*/
console.log("Are `a[0]` and `b` the same object:", a[0] === b); // -> true

/*
We create a new array, lets call it Object 3.
We explicitly tell Javascript to use `b` to 
refer to Object 3 from this point forward.
*/
b = [2];
/*
Notice that `a[0]` still refers to Object 2.
*/
console.log("Are `a[0]` and `b` the same object:", a[0] === b); // -> false

/*
We can explicitly tell javascript to update `a` by 
using the assignment operator.
*/
a[0] = b;
console.log("Are `a[0]` and `b` the same object:", a[0] === b); // -> true

1赞 Alex Khismatulin 4/21/2022 #2

这与局部/全局范围无关。

顶级域名

调用数组时,会将项添加到现有数组。使用赋值时,将创建一个新数组,该数组与之前存储在变量中的数组无关。push

详细

代码中发生的情况如下:

步骤 1。 let valueArr = [0,0];

将数组分配给变量时,会发生以下两种情况:

  1. 正在创建数组并将其保存在内存中([0,0])
  2. 该变量保存对所创建数组的引用valueArr

第2步。 newArr.push(valueArr);

然后,将数组推入数组。现在包含一个与 具有相同引用的元素。它们都指向数组。valueArrnewArrnewArr[0]valueArr[0,0]

第 3 步。 valueArr.push(0);

在此步骤中,我们将一个元素推送到引用的数组中。由于引用了相同的数组,因此也会更新。valueArrnewArrnewArr[0]

第 4 步。 valueArr = [0,0,0];

在这里,我们重复步骤1。创建一个新数组并保存其对 的引用。问题是我们更改了存储在 中的引用,但仍然指向旧数组。这就是为什么你看不到任何更新的原因:这是一个完全不同的数组。valueArrvalueArrnewArr[0]

如果您想了解有关引用类型的更多信息,这将是一个良好的开端: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

评论

0赞 Guilherme Pinheiro 4/21/2022
谢谢,亚历克斯!非常清楚的答案。我想我现在明白了!