为什么在 JavaScript 中对数组 'B' 的更改会传播到数组 'A'(用于定义 'B' 但此后从未直接修改过)?

Why do changes to an array 'B' in JavaScript spread to an array 'A' (which was used to define 'B' but thereafter never directly modified)?

我创建了一个名为 'alphabet' 的常量并将其分配给一个包含字母表前 5 个字母的数组。然后我想有一个函数可以为数组中的每个字符添加一个数字,以枚举它们。但是,我不想修改原始 'alphabet' 数组中的值,所以我在我的枚举函数中创建了一个 'temp' 变量,并且只对其进行了更改。但是,我对 'temp' 所做的任何更改都会扩展到 'alphabet'。我不明白为什么,我想防止这种情况发生。

这是我的代码:(还有 available on CodePen

const alphabet = ["a", "b", "c", "d", "e"];

function alphaPosition(seq) {
  //'temp' gets 'seq' to avoid making changes directly on the provided argument.
  let temp = seq;
  //adds indexes to each element in the 'temp' array:
  for (let i = 1; i <= temp.length; i++) {
    temp[i - 1] = temp[i - 1] + i;
  }
  return temp;
}

console.log(
  "Step 1. 'alphabet' array before running the 'alphaPosition' function:"
);
console.log(alphabet);
console.log(
  "Step 2. This is the final value of 'temp' in 'alphaPosition' after running the function. An index has been added to every element in the array, as expected:"
);
console.log(alphaPosition(alphabet));
console.log(
  "Step 3. Here's the 'alphabet' array after running 'alphaPosition'. Indexes have also been added to every element, despite not modifying the function argument directly:"
);
console.log(alphabet);

输出:

/*
-> Step 1. 'alphabet' array before running the 'alphaPosition' function:
-> ["a", "b", "c", "d", "e"]
-> Step 2. This is the final value of 'temp' in 'alphaPosition' after running the function. An index has been added to every element in the array, as expected:
-> ["a1", "b2", "c3", "d4", "e5"]
-> Step 3. Here's the 'alphabet' array after running 'alphaPosition'. Indexes have also been added to every element, despite not modifying the function argument directly:
-> ["a1", "b2", "c3", "d4", "e5"]
*/

为什么 'temp' 的更改会传播到 'alphabet'?我希望,因为我将 'alphabet' 定义为常量,所以甚至不可能修改它。此外,我从不在我的函数中对其进行更改。我只用它来定义'temp'。有什么办法可以防止这些传播的发生吗?

我尝试用数字 const 而不是数组来做类似的事情,一切都按预期进行:

const number = 10;

function numChange(n) {
  //'virtualN' gets 'n' to avoid making changes directly on the provided argument.
  let virtualN = n;
  //modify 'virtualN' multiple times to emulate what was done to the 'temp' array in the alphaPosition function.
  for (let i = 1; i <= 5; i++) {
    virtualN = "iteration" + i;
  }
  return virtualN;
}

console.log(
  "Step 1. See the value of 'number' before running the numChange function:"
);
console.log(number);
console.log(
  "Step 2. This is the final value of 'virtualN' in 'numChange(number)' after running the function. As expected, it's been modified from its initual value by the 'for' loop:"
);
console.log(numChange(number));
console.log(
  "Step 3. Finally, we can see the value of 'number' is still the same as before running the numChange function. As expected, only the value of virtualN changed while the argument 'n' suffered no modifications:"
);
console.log(number);

输出:

/*
-> Step 1. See the value of 'number' before running the numChange function:    
-> 10     
-> Step 2. This is the final value of 'virtualN' in 'numChange(number)' after running the function. As expected, it's been modified from its initual value by the 'for' loop:  
-> iteration5
-> Step 3. Finally, we can see the value of 'number' is still the same as before running the numChange function. As expected, only the value of virtualN changed while the argument 'n' suffered no modifications:
-> 10
*/

为什么使用中间变量来避免对数字而不是数组的原始工作进行更改?

如果您对此提供任何帮助或澄清,我将不胜感激。 I've added my code to this CodePen 如果您想对其进行调整或进行更多试验。 提前感谢您的帮助。

这是关于 javascript 中赋值的工作方式。给定以下代码:

const a = { foo: "bar" };
const b = a;

变量ab都指向同一个对象。这意味着内存中只有一个对象,并且当您尝试使用 b 访问对象时,改变对象 a 指向将被反映出来,反之亦然。例如:

const a = { foo: "bar" };
const b = a;

a.foo = "baz";

console.log(a);
console.log(b);

那么现在,我们如何才能避免这种情况发生呢?我们可以通过将 a 浅拷贝 分配给 b 来做到这一点。这可以通过几种不同的方式完成,下面使用展开运算符 (...):

const a = { foo: "bar" };
const b = { ...a };

a.foo = "baz";

console.log(a);
console.log(b);

所以现在,内存中有两个不同的对象。您会注意到我将此称为 复制,这很重要:如果您有深层对象,则需要进行深层复制以完成相同类型的解耦。

如何根据您的具体情况解决此问题:

您的具体情况的 TLDR 是您的临时变量应该是数组的浅表副本,而不是对现有数组的引用:

let temp = [...seq];

这似乎是 this 的副本。 基本答案是 here.

我在下面解释原因:

似乎对于字符串和数字,javascript是按值传递,而数组等对象是按引用传递。

这意味着在您的第一个示例中;该函数正在引用原始数组,当您执行 let temp = seq 时,temp 实际上只是指向传入的原始对象的指针。在本例中为 alphabet,因此当您修改 temp 时;它实际上是在修改字母表。

按值传递只是将值发送给函数,因此原始变量与您的数字示例中的相同。

为了获得预期的结果,您需要对数组进行深度复制,例如 let temp = deepCopy(seq)

使用const我想可能只是让用户知道不要修改它的语法,有些编辑器不会让你在代码中重新修改const,但在这种情况下它以迂回的方式发生.