数组可变性和变量引用场景不清楚

Array mutability and variable reference scenario is unclear

所以,我知道 JavaScript 中的数组是可变的。

意味着如果我创建数组a和数组b = a,那么如果我修改数组a,修改在数组b中也是可见的。

但是,在下面的场景中,我不明白为什么 b 将 "reference" 丢失到数组 a

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

console.log('a =', a);
console.log('b =', b);

a[0] = 4;
console.log('a =', a);
console.log('b =', b);

a = [5,5];
console.log('a =', a);
console.log('b =', b);

ab 不是对彼此的引用 - 它们是对 相同数组 的引用。

当您执行 a = [5,5] 时,您将 a 设置为一个完全 新的 数组,而 b 仍然指的是旧数组。

让我们看看计算机内存¹。首先,创建了两个变量,ab。这些基本上是内存位置,其中填充了一个值:

 location | name²      |  value
 -------------------------------------
  1       |  a         |  undefined
  2       |  b         |  undefined

现在 a 已初始化,并创建了一个新数组。然而,该数组并没有直接存储在变量下,而是在另一个位置,在 a 内,只有对该位置的引用:

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 3
  2        |  b         |  undefined
  3        |            |  [1, 2, 3]

现在,当您执行 b = a 时,引用会被复制,您最终会在:

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 3
  2        |  b         |  ➡️ 3
  3        |            |  [1, 2, 3]

现在,当您执行 a = [5,5] 时,会创建另一个数组,并且 a 会引用它。 b 虽然没有改变,它仍然引用另一个数组。

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 4
  2        |  b         |  ➡️ 3
  3        |            |  [1, 2, 3]
  4        |            |  [5, 5]

或者如果你这样做 b = {value: a} :

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 4
  2        |  b         |  ➡️ 5
  3        |            |  [1, 2, 3] // waiting for GC
  4        |            |  [5, 5]
  5        |            | { value: ➡️4 }

¹ 是的,JavaScript 是一种解释型语言,因此您无法确定它最终如何出现在内存中,这取决于引擎。然而,JS 的概念是从其他语言中衍生出来的,这就是为什么在低层次上思考通常是有帮助的。

² 没有特定内存位置的名称这样的东西,我只是为了清楚起见才添加的。

将“变量”与“值”区分开来可能会有所帮助。

ab 在你的例子中是变量。

[1,2,3]4[5,5] 在您的示例中是值。

多个变量可以引用同一个值。如果该值发生变化(变异),则引用该值的任何和所有变量都将 return 更改后的值。下面的示例将 ab 的引用设置为相同的值,然后通过 a 的引用和 b 的引用对该值进行更改。结果是更改后的值仍然被两个变量引用。

var a = [1, 2, 3]; // a references the value [1,2,3]
var b = a; // b references the value [1,2,3]
a[0] = 4; // [1,2,3] changed to [4,2,3]
b[1] = 5; // [1,2,3] changed to [4,5,3]
console.log(a); // [4,5,3]
console.log(b); // [4,5,3]

但是,您可以通过将变量“分配”给新值来完全更改变量引用的值。这不会改变(变异)值本身,也不会改变碰巧引用相同值的任何其他变量的引用。下面的示例将 ab 的引用设置为相同的值,然后将 a 的引用更改为新值。结果是变量现在引用不同的值。

var a = [1, 2, 3]; // a references the value [1,2,3]
var b = a; // b references the value [1,2,3]
a = [5, 5]; // a reference assigned to new value [5,5]
console.log(a); // [5,5]
console.log(b); // [1,2,3]