为什么JavaScript中对数组'B'的修改会扩散到数组'A'(它被用来定义'B',但此后从未直接修改)?[重复]

问题描述 投票:0回答:1

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

这是我的代码。(还有 可在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'。我只用它来定义'temp'。有什么办法可以防止这些传播的发生吗?

我曾尝试用一个数值常量代替数组来做类似的事情,结果一切都能如愿。

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
*/

为什么使用一个中间变量来避免对原始变量进行修改 对数字来说是可行的 而对数组来说就不行了?

我非常感谢任何关于这个问题的帮助或澄清。我已经把我的代码添加到这个CodePen中了 以防你想调整它或做更多的实验.先谢谢你的帮助。

javascript arrays variables constants scoping
1个回答
0
投票

这是关于javascript中的赋值是如何工作的。给出以下代码。

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

变量 ab 都指向同一个对象。这意味着在内存中只有一个对象,而突变这个对象 a 所指向的对象,当你尝试使用 b 反之亦然。例如:

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

a.foo = "baz";

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

那么现在,我们如何让这种情况不发生?我们可以通过将一个 浅尝辄止ab. 这可以通过几种不同的方式来实现,下面使用传播操作符(...)。

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

a.foo = "baz";

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

所以现在,内存里有两个不同的对象。你会注意到我把它叫做 复制,这一点很重要:如果你有深层对象,你就需要深层复制来完成同样的解耦。

如何在你的具体情况下解决这个问题。

针对你的具体情况的TLDR是,你的临时变量应该是数组的浅层拷贝,而不是对现有数组的引用。

let temp = [...seq];

-1
投票

这似乎是重复的 这个.而基本的答案是 此处.

下面我解释一下原因。

似乎对于字符串和数字,javascript是通过值来传递的, 而像数组这样的对象是通过引用来传递的。

这意味着在你的第一个例子中,函数是对原始数组的引用,当你做 let temp = seqtemp实际上只是一个指向传入的原始对象的指针。在这种情况下,就是 alphabet 所以当你修改temp的时候,实际上是在修改字母表。

Pass by value只是把值发送给函数,所以原始变量和你的数字例子中的变量保持不变。

为了得到你想要的结果,你需要对你的数组做一个Deep Copy,比如说 let temp = deepCopy(seq).

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

© www.soinside.com 2019 - 2024. All rights reserved.