6

In a class I am taking they give an example of editing an Array's contents with a forEach() loop.

Classes Example:

var donuts = ["jelly donut", "chocolate donut", "glazed donut"];

donuts.forEach(function(donut) {
  donut += " hole";
  donut = donut.toUpperCase();
  console.log(donut);
});

Prints:
JELLY DONUT HOLE
CHOCOLATE DONUT HOLE
GLAZED DONUT HOLE

The problem is when I try to solve a quiz problem using the same technique it doesn't change the arrays values. I believe this has to do with the if statement but they ask us to use it, so why would they not tell us there is an issue?

My Code:

/*
 * Programming Quiz: Another Type of Loop (6-8)
 *
 * Use the existing `test` variable and write a `forEach` loop
 * that adds 100 to each number that is divisible by 3.
 *
 * Things to note:
 *  - you must use an `if` statement to verify code is divisible by 3
 *  - you can use `console.log` to verify the `test` variable when you're finished looping
 */

var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
    19, 300, 3775, 299, 36, 209, 148, 169, 299,
    6, 109, 20, 58, 139, 59, 3, 1, 139
];

test.forEach(function(element){
    if (element % 3 === 0){
        element += 100;
        return element
    }
});

console.log(test);

I have tried running return statements but no luck. I reached out to their "Live Help" but they were less than helpful. Can someone please tell me what I am not seeing here?

yohohosilver
  • 367
  • 1
  • 2
  • 15
  • 3
    Shouldn’t you use `map`? `forEach` is not appropriate in this scenario. `donut` is passed into the callback function by value, not by reference. Editing `donut` only edits the local copy of that string. If `donut` were an object, you could actually mutate it, because those are passed by reference. The classes’ example doesn’t change the original array as well. – Sebastian Simon Oct 16 '17 at 02:29
  • 5
    `return` in `forEach` does nothing... nowhere to return to – charlietfl Oct 16 '17 at 02:31
  • 1
    `map` doesn't modify the array either, it creates a new one. – kamoroso94 Oct 16 '17 at 02:32
  • I'm just doing what they tell me. I'm just skipping this and deleting the question. Thank you for pointing that out! They aren't very clearly asking what they want here. – yohohosilver Oct 16 '17 at 02:33
  • 1
    You could leave it for future people to learn from. – kamoroso94 Oct 16 '17 at 02:34
  • I see. It is a common class, Udacity, so I will. Just figured it will start getting downvotes for being a "stupid" question. – yohohosilver Oct 16 '17 at 02:34
  • See https://stackoverflow.com/questions/23964111/does-foreach-bind-by-reference. –  Oct 16 '17 at 02:40
  • The variable scope is the problem here, in the class example they log the result in the method, but in yours you're looking to change the initial value of the original array. If you were to put the console log in the class example you'd see that it also is unchanged, because the scope of `donut` and `element` is limited to that method call. The various answers below show you how to affect the `test` variable which is global in relation to this method. – Dave Goten Oct 16 '17 at 02:41

3 Answers3

14

The forEach method of an array does not modify the array, it just iterates over it. When you change the argument in the callback function, that doesn't affect the array either. Also, forEach doesn't do anything with the return values from the callback. Once you calculate the value you want to use to replace, you can set it using the index and array arguments, like so.

var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
    19, 300, 3775, 299, 36, 209, 148, 169, 299,
    6, 109, 20, 58, 139, 59, 3, 1, 139
];

test.forEach(function(element, index, array){
    if (element % 3 === 0){
        element += 100;
        array[index] = element;
    }
});

console.log(test);
kamoroso94
  • 1,713
  • 1
  • 16
  • 19
  • 2
    Thank you. I think this is what they are asking for, but they sure don't explain any of this beforehand. I really appreciate it. – yohohosilver Oct 16 '17 at 02:38
  • 3
    This answer is fine as far as it goes, but seems woefully incomplete without mentioning `map`. –  Oct 16 '17 at 02:39
  • 1
    I don't feel like `map` was the right method for the job, and so I didn't mention it. Neither do I feel `reduce` or any other array iterator method does any better than `forEach` does, so I left it at that. – kamoroso94 Oct 16 '17 at 04:49
4

You're not passing the reference for each value into the callback, just the value. So you're updating a local value without actually editing the array.

You can update the array by passing the index into the callback and then editing the value at that index.

test.forEach(function(element,index){ 
    if (element % 3 === 0){ 
        test[index] = element + 100; 
    } 
});
SteveKitakis
  • 162
  • 2
0

just pass the index on the array then it will be modified.

var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
19, 300, 3775, 299, 36, 209, 148, 169, 299,
6, 109, 20, 58, 139, 59, 3, 1, 139
];

test.forEach(function(element, index){
    if (element % 3 === 0){
        test[index] += 100;
    }
});

console.log(test);
Riyenz
  • 2,498
  • 2
  • 9
  • 23
  • 2
    Actually, this is poor practice. If you want to modify the elements of an array, that's what `map` is for. –  Oct 16 '17 at 02:42