forEach()方法是否通过引用绑定?

23
var arr = ['Foo'];

arr.forEach(function(item){
  console.log(item);
  item = 'Lorem';
  console.dir(arr[0]);

});

for (var item in arr){
  arr[item] = 'Ipsum';
  console.dir(arr[0]);
}

就像上面的代码所示,我注意到将项目的值更改后传递给 forEach() 回调函数不会导致迭代对象发生变化。

使用for...in确实会有所改变。

为什么会这样,我应该如何更改数组中的值?

我发现在MDN上,涉及此主题的内容相当令人困惑。


for..in 中属性被访问的顺序完全取决于实现。 forEach 仅访问从0到length的数字属性,并严格按照数字顺序,与值无关。MDN的链接已经失效,也许你是指这个链接 - RobG
4
你能否把你的代码放在这里,而不是其他网站上? - cookie monster
3个回答

28

使用for...in循环确实会这样。

不会。你的forEach循环等同于这个for...in循环(除了顺序):

for (var index in arr) {
  var item = arr[index];
  console.log(item);
  item = 'Lorem';
  console.dir(arr[0]);
}

你看到了吗,这个数组也没有被修改?这是因为JavaScript始终采用按值传递方式,需要记住一个非常简单的规则:

将一个值赋给一个变量永远不会更改另一个变量或数据结构的值。

这意味着,将新值赋给item不能更改arr中的元素。如果您想修改数组,则必须直接对其进行更改,即通过分配值给索引来进行突变。

arr[index] = 'foo';

8
我发现这样说容易让人感到困惑,因为对象是按引用传递的。 - Wottensprels
1
@Sprottenwels:不,这是正确的。JavaScript 只有值传递。在 JavaScript 中,唯一的值是原始数据类型和对象指针。 "对象" 不是值,也不能被 "传递"。 - newacct
@Sprottenwels:这很令人困惑,但是按引用传递有一个不同且非常具体的含义。您可以在维基百科文章中阅读相关内容。还可以查看按共享传递部分,它更接近JS的工作方式,但这不是一个非常常见的术语。 - Felix Kling

17

在你的情况下,item 变量是按值传递的,因为它是一个原始值。如果它是一个 JSON 对象,并且您更改了其中一个属性,则会反映在原始列表中。

在这种情况下,您可以使用 forEach 具有的其他参数。例如:

arr.forEach(element, index, array) {
    ...
}

通过使用这些参数,您可以直接影响array[index]


正是我所需要的。谢谢! - José Manuel Blasco

13

注意,在 forEach 中的回调函数有三个参数,第二个是当前元素的索引,第三个是数组本身。如果你想修改数组,可以使用这两个参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接