Reputation: 29397
example:
var arr = ["one","two","three"];
arr.forEach(function(part){
part = "four";
return "four";
})
alert(arr);
The array is still with its original values, is there any way to have writing access to array's elements from the iterating function?
Upvotes: 484
Views: 721802
Reputation: 3390
You can try this if you want to override.
var newArray = [444,555,666];
var oldArray = [11,22,33];
oldArray.forEach(
(name, index) => oldArray[index] = newArray[index]
);
console.log(newArray);
Upvotes: 1
Reputation: 206505
Array: [1, 2, 3, 4]
Result: ["foo1", "foo2", "foo3", "foo4"]
Array.prototype.map()
Keep original arrayconst originalArr = ["Iron", "Super", "Ant", "Aqua"];
const modifiedArr = originalArr.map(name => `${name}man`);
console.log( "Original: %s", originalArr );
console.log( "Modified: %s", modifiedArr );
Array.prototype.map()
Override original arraylet originalArr = ["Iron", "Super", "Ant", "Aqua"];
originalArr = originalArr.map(name => `${name}man`);
console.log( "Original: %s", originalArr );
Array.prototype.forEach()
Override original arrayconst originalArr = ["Iron", "Super", "Ant", "Aqua"];
originalArr.forEach((name, index) => originalArr[index] = `${name}man`);
console.log( "Overridden: %s", originalArr );
Upvotes: 165
Reputation: 146170
If the change you need to make is to completely remove one or more items from the list you're safer using a for
loop and going backwards through the loop.
for (let i = myArray.length - 1; i >= 0; i--)
{
const item = myArray[i];
if (...)
{
// remove item
// https://stackoverflow.com/questions/5767325/how-can-i-remove-a-specific-item-from-an-array?rq=1
}
};
Going backwards means that the array of each item never changes. If you are going forwards through a loop and delete item[3]
then item[4]
is now the new item[3]
, which doesn't make anything easier. You won't have that issue going backwards.
This is of course a solution not using foreach, but it's important to remember that 'old school' ways can often be best. And if for whatever reason you need to break;
from the loop (and there are more than a handful of items) a for loop is more efficient since you can't break out of a for loop.
Upvotes: 2
Reputation: 413966
The callback is passed the element, the index, and the array itself.
arr.forEach(function(part, index, theArray) {
theArray[index] = "hello world";
});
edit — as noted in a comment, the .forEach()
function can take a second argument, which will be used as the value of this
in each call to the callback:
arr.forEach(function(part, index) {
this[index] = "hello world";
}, arr); // use arr as this
That second example shows arr
itself being set up as this
in the callback.One might think that the array involved in the .forEach()
call might be the default value of this
, but for whatever reason it's not; this
will be undefined
if that second argument is not provided.
(Note: the above stuff about this
does not apply if the callback is a =>
function, because this
is never bound to anything when such functions are invoked.)
Also it's important to remember that there is a whole family of similar utilities provided on the Array prototype, and many questions pop up on Stackoverflow about one function or another such that the best solution is to simply pick a different tool. You've got:
forEach
for doing a thing with or to every entry in an array;filter
for producing a new array containing only qualifying entries;map
for making a one-to-one new array by transforming an existing array;some
to check whether at least one element in an array fits some description;every
to check whether all entries in an array match a description;find
to look for a value in an arrayand so on. MDN link
Upvotes: 730
Reputation: 2033
Here's a similar answer using using a =>
style function:
var data = [1,2,3,4];
data.forEach( (item, i, self) => self[i] = item + 10 );
gives the result:
[11,12,13,14]
The self
parameter isn't strictly necessary with the arrow style function, so
data.forEach( (item,i) => data[i] = item + 10);
also works.
Upvotes: 12
Reputation: 2038
To add or delete elements entirely which would alter the index, by way of extension of zhujy_8833 suggestion of slice() to iterate over a copy, simply count the number of elements you have already deleted or added and alter the index accordingly. For example, to delete elements:
let values = ["A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"];
let count = 0;
values.slice().forEach((value, index) => {
if (value === "A2" || value === "A5") {
values.splice(index - count++, 1);
};
});
console.log(values);
// Expected: [ 'A0', 'A1', 'A3', 'A4', 'A6', 'A7', 'A8' ]
To insert elements before:
if (value === "A0" || value === "A6" || value === "A8") {
values.splice(index - count--, 0, 'newVal');
};
// Expected: ['newVal', A0, 'A1', 'A2', 'A3', 'A4', 'A5', 'newVal', 'A6', 'A7', 'newVal', 'A8' ]
To insert elements after:
if (value === "A0" || value === "A6" || value === "A8") {
values.splice(index - --count, 0, 'newVal');
};
// Expected: ['A0', 'newVal', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'newVal', 'A7', 'A8', 'newVal']
To replace an element:
if (value === "A3" || value === "A4" || value === "A7") {
values.splice(index, 1, 'newVal');
};
// Expected: [ 'A0', 'A1', 'A2', 'newVal', 'newVal', 'A5', 'A6', 'newVal', 'A8' ]
Note: if implementing both 'before' and 'after' inserts, code should handle 'before' inserts first, other way around would not be as expected
Upvotes: 3
Reputation: 26191
With the Array object methods you can modify the Array content yet compared to the basic for loops, these methods lack one important functionality. You can not modify the index on the run.
For example if you will remove the current element and place it to another index position within the same array you can easily do this. If you move the current element to a previous position there is no problem in the next iteration you will get the same next item as if you hadn't done anything.
Consider this code where we move the item at index position 5 to index position 2 once the index counts up to 5.
var ar = [0,1,2,3,4,5,6,7,8,9];
ar.forEach((e,i,a) => {
i == 5 && a.splice(2,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 6 - 7 7 - 8 8 - 9 9
However if we move the current element to somewhere beyond the current index position things get a little messy. Then the very next item will shift into the moved items position and in the next iteration we will not be able to see or evaluate it.
Consider this code where we move the item at index position 5 to index position 7 once the index counts up to 5.
var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && a.splice(7,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 7 - 7 5 - 8 8 - 9 9
So we have never met 6 in the loop. Normally in a for loop you are expected decrement the index value when you move the array item forward so that your index stays at the same position in the next run and you can still evaluate the item shifted into the removed item's place. This is not possible with array methods. You can not alter the index. Check the following code
var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && (a.splice(7,0,a.splice(i,1)[0]), i--);
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 4 5 - 6 7 - 7 5 - 8 8 - 9 9
As you see when we decrement i
it will not continue from 5 but 6, from where it was left.
So keep this in mind.
Upvotes: 2
Reputation: 2134
Let's try to keep it simple and discuss how it is actually working. It has to do with variable types and function parameters.
Here is your code we are talking about:
var arr = ["one","two","three"];
arr.forEach(function(part) {
part = "four";
return "four";
})
alert(arr);
First off, here is where you should be reading about Array.prototype.forEach():
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
Second, let's talk briefly about value types in JavaScript.
Primitives (undefined, null, String, Boolean, Number) store an actual value.
ex: var x = 5;
Reference Types (custom objects) store the memory location of the object.
ex: var xObj = { x : 5 };
And third, how function parameters work.
In functions, parameters are always passed by value.
Because arr
is an array of Strings, it's an array of primitive objects, which means they are stored by value.
So for your code above, this means that each time the forEach() iterates, part
is equal to the same value as arr[index]
, but not the same object.
part = "four";
will change the part
variable, but will leave arr
alone.
The following code will change the values you desire:
var arr = ["one","two","three"];
arr.forEach(function(part, index) {
arr[index] = "four";
});
alert(arr);
Now if array arr
was an array of reference types, the following code will work because reference types store a memory location of an object instead of the actual object.
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);
The following illustrates that you can change part
to point to a new object while leaving the objects stored in arr
alone:
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);
Upvotes: 162
Reputation: 571
The .forEach function can have a callback function(eachelement, elementIndex) So basically what you need to do is :
arr.forEach(function(element,index){
arr[index] = "four"; //set the value
});
console.log(arr); //the array has been overwritten.
Or if you want to keep the original array, you can make a copy of it before doing the above process. To make a copy, you can use:
var copy = arr.slice();
Upvotes: 5
Reputation: 1462
replace it with index of the array.
array[index] = new_value;
Upvotes: 2
Reputation: 120288
Javascript is pass by value, and which essentially means part
is a copy of the value in the array.
To change the value, access the array itself in your loop.
arr[index] = 'new value';
Upvotes: 18