在javascript中执行foreach时是否可以更改数组的值?

rsk*_*k82 261 javascript arrays foreach pass-by-reference

例:

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

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

alert(arr);
Run Code Online (Sandbox Code Playgroud)

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

Poi*_*nty 400

回调传递元素,索引和数组本身.

arr.forEach(function(part, index, theArray) {
  theArray[index] = "hello world";
});
Run Code Online (Sandbox Code Playgroud)

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

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

第二个示例显示arr自己this在回调中设置.有人可能认为.forEach()调用中涉及的数组可能是默认this,但无论出于何种原因,它都不是; thisundefined如果没有提供第二个参数.

同样重要的是要记住,在Array原型上提供了一整套类似的实用程序,Stackoverflow上有很多关于一个或多个函数的问题,最好的解决方案就是选择一个不同的工具.你有:

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

等等.MDN链接

  • 谢谢!ES6:arr.forEach((o,i,a)=> a [i] = myNewVal) (21认同)
  • 要使用作为第二个参数传递给this.forEach()的参数,您需要使用语法function()传递回调函数,因为使用ES6的箭头函数`()=> {}`不会绑定上下文。 (3认同)
  • 为了完整性,`.forEach()`还接受第二个参数`thisArg`,您可以在回调中将其用作`this`。注意:这是`.forEach`的参数,而不是回调的参数。 (2认同)

Dav*_*ave 121

让我们试着保持简单,并讨论它是如何工作的.它与变量类型和函数参数有关.

这是我们正在讨论的代码:

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

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

alert(arr);
Run Code Online (Sandbox Code Playgroud)

首先,这里是您应该阅读的有关Array.prototype.forEach()的内容:

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

其次,让我们简单地谈谈JavaScript中的值类型.

Primitives(undefined,null,String,Boolean,Number)存储实际值.

例如: var x = 5;

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

例如: var xObj = { x : 5 };

第三,函数参数如何工作.

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

因为arr是一个字符串数组,它是一个原始对象数组,这意味着它们是按值存储的.

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

part = "four";将改变part变量,但将arr独自留下.

以下代码将更改您想要的值:

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

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

alert(arr);
Run Code Online (Sandbox Code Playgroud)

现在,如果array 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);
Run Code Online (Sandbox Code Playgroud)

以下说明您可以更改part为指向新对象,同时保留arr单独存储的对象:

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);
Run Code Online (Sandbox Code Playgroud)

  • 的确,很好的解释!在其他迭代方法中扩展解释会更好...对于...,map,...对于这类情况,工作的新方式与forEach非常相似,除了"最终改变原始数组(如在forEach中)缺少索引".此外,ES5映射看起来与forEach类似,可能只是从映射返回值的可能性使得从语法角度来看比使用索引更清晰. (2认同)

Rok*_*jan 80

数组:[1, 2, 3, 4]
结果:["foo1", "foo2", "foo3", "foo4"]

Array.prototype.map() 保留原始阵列

通过引入一个新变量来实现 Array.prototype.forEach()

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
const modifiedArr = originalArr.map(name => `${name}man`);

console.log( "Original: %s", originalArr );
console.log( "Modified: %s", modifiedArr );
Run Code Online (Sandbox Code Playgroud)

[1, 2, 3, 4] 修改原始数组

通过重新分配["foo1", "foo2", "foo3", "foo4"]变量来实现

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
originalArr.forEach((name, index) => originalArr[index] = `${name}man`);

console.log( "Overridden: %s", originalArr );
Run Code Online (Sandbox Code Playgroud)

Array.prototype.map() 修改原始数组

通过索引来定位它的键来实现 Array.prototype.forEach()

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
const modifiedArr = originalArr.map(name => `${name}man`);

console.log( "Original: %s", originalArr );
console.log( "Modified: %s", modifiedArr );
Run Code Online (Sandbox Code Playgroud)

  • “Array.prototype.map() 修改原始数组,通过重新分配arr变量实现” .map() 永远不会修改原始数组,而是创建一个新数组。变量的重新分配不会改变原始对象。 (3认同)
  • @SebastianSimon,感谢您的回复。我想添加的是,forEach 会覆盖数据,但地图不能,它会创建一个新副本。 (2认同)

hvg*_*des 13

Javascript是按值传递的,它实质上意味着part是数组中值的副本.

要更改值,请在循环中访问数组本身.

arr[index] = 'new value';

  • 不是一个粗略的概括.一个完全正确和绝对的陈述.Javascript按值传递引用.Javascript总是按值传递. (9认同)
  • 说"JavaScript是通过价值传递"是一个粗略的概括.JavaScript中有引用类型.值类型按值传递. (8认同)
  • @Bergi只是因为一个语言有一个叫做引用的东西,并不意味着它使用pass by reference.引用可以(并且)通过值传递,即复制引用的值并将该副本用作参数. (6认同)

J. *_*son 7

这是使用=>样式函数的类似答案:

var data = [1,2,3,4];
data.forEach( (item, i, self) => self[i] = item + 10 );
Run Code Online (Sandbox Code Playgroud)

给出结果:

[11,12,13,14]
Run Code Online (Sandbox Code Playgroud)

self参数不与箭头样式功能绝对必要的,所以

data.forEach( (item,i) => data[i] = item + 10);
Run Code Online (Sandbox Code Playgroud)

也有效。


小智 5

.forEach 函数可以有一个回调函数(eachelement, elementIndex) 所以基本上你需要做的是:

arr.forEach(function(element,index){
    arr[index] = "four";   //set the value  
});
console.log(arr); //the array has been overwritten.
Run Code Online (Sandbox Code Playgroud)

或者,如果您想保留原始数组,可以在执行上述过程之前复制它。要制作副本,您可以使用:

var copy = arr.slice();
Run Code Online (Sandbox Code Playgroud)

  • 如果要复制数组,请使用“map()”而不是“forEach()”。`map()` 迭代源数组并返回一个包含原始数组的[修改]副本的新数组:源数组保持不变。 (3认同)