在执行 foreach 时更改数组中的值

例:

var arr = ["one","two","three"];

arr.forEach(function(part){
  part = "four";
  return "four";
})

alert(arr);

数组仍然具有其原始值,有没有办法从迭代函数中写入数组的元素?


答案 1

回调传递元素、索引和数组本身。

arr.forEach(function(part, index, theArray) {
  theArray[index] = "hello world";
});

edit — 如注释中所述,该函数可以采用第二个参数,该参数将用作每次调用回调的值:.forEach()this

arr.forEach(function(part, index) {
  this[index] = "hello world";
}, arr); // use arr as this

第二个示例显示其设置方式与回调相同。有人可能会认为调用中涉及的数组可能是 的默认值,但无论出于何种原因,它都不是; 如果未提供第二个参数,则为。arrthis.forEach()thisthisundefined

(注意:如果回调是函数,则上述内容不适用,因为在调用此类函数时永远不会绑定到任何内容。this=>this

同样重要的是要记住,Array原型上提供了一整套类似的实用程序,Stackoverflow上弹出了许多关于一个或另一个函数的问题,因此最好的解决方案是简单地选择一个不同的工具。你有:

  • forEach用于对数组中的每个条目执行操作;
  • filter用于生成仅包含合格条目的新数组;
  • map通过转换现有数组来制作一对一的新数组;
  • some检查数组中是否有至少一个元素符合某些描述;
  • every检查数组中的所有条目是否都与描述匹配;
  • find在数组中查找值

等等。MDN链接


答案 2

让我们尽量保持简单,并讨论它的实际工作原理。它与变量类型和函数参数有关。

以下是我们正在谈论的代码:

var arr = ["one","two","three"];

arr.forEach(function(part) {
  part = "four";
  return "four";
})

alert(arr);

首先,这是你应该阅读 Array.prototype.forEach() 的地方:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

其次,让我们简要地谈谈 JavaScript 中的值类型。

基元(未定义、空值、字符串、布尔值、数字)存储实际值。

前任:var x = 5;

引用类型(自定义对象)存储对象的内存位置。

前任:var xObj = { x : 5 };

第三,函数参数的工作原理。

在函数中,参数始终按值传递。

因为它是 Strings 的数组,所以它是基元对象的数组,这意味着它们是按值存储的。arr

因此,对于上面的代码,这意味着每次 forEach() 迭代时,都等于 与 相同的值,但不是相同的对象partarr[index]

part = "four";将更改变量,但将单独离开。partarr

以下代码将更改所需的值:

var arr = ["one","two","three"];

arr.forEach(function(part, index) {
  arr[index] = "four";
});

alert(arr);

现在,如果数组是引用类型的数组,则下面的代码将起作用,因为引用类型存储对象的内存位置而不是实际对象。arr

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // part and arr[index] point to the same object
  // so changing the object that part points to changes the object that arr[index] points to

  part.num = "four";
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);

下面说明了您可以更改为指向新对象,同时将对象单独存储在中:partarr

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // the following will not change the object that arr[index] points to because part now points at a new object
  part = 5;
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);