1

My question relates to a JavaScript function I have written that seems to be behaving a bizarre way. In summary, the function execution seems to go on even after a return statement is encountered - it's as if the return statement inside a forEach loop is ignored. This is difficult to make sense of, and is not how it happens in any of the languages I have seen before.

Presenting a code snippet below - I have tried to make the code, logging and comments as focused and descriptive as possible so that the reader can easily identify the issue. However, I am sharing a detailed description of the problem as well if you'd prefer not to jump to the code directly.

In the code I have shared, the function substituteWithMainColor() takes a string value named color as argument. It matches it against each element of an array (called substitutionArray) of object literals, where each such object contains a member string called mainColor and member array called variations. If the function finds the color argument in any of the variations arrays, then it returns the corresponding mainColor of the object in which the match was found. If no match is found in any of the objects, then the function returns the original value passed as argument.

In my example, an argument "Cyan" is passed to the function substituteWithMainColor(). Since the array substitutionArray contains "Cyan" as one of the strings in the variations array of its third item, a match is found ( and the logs show it). However, at this point, instead of returning with the matched mainColor value "Blue" as expected, the function ignores the return statement inside the forEach() loop and keeps on executing further iterations of the forEach loop (the logs show this, too). Eventually it executes the final return statement which is after the forEach() loop, and returns the original color value, which is erroneous.

Can someone please help me understand what might be going on?

 const substitutionArray = [
            { mainColor: "Red", variations: ["Magenta", "Orange", "Crimson", "Coral", "Maroon"] },
            { mainColor: "Blue", variations: ["Purple", "Violet", "Cyan"] },
            { mainColor: "Green", variations: ["Teal", "Lime", "Aquamarine", "Olive"] }
        ]

        function substituteWithMainColor(color) {
            logToPage(`In substituteWithMainColor() function. Input: ${color}`);
            substitutionArray.forEach(item => {
                logToPage(`Testing input ${color} against variations of ${item.mainColor}`)
                if (item.variations.includes(color)) {
                    logToPage(`FOUND MATCH for ${color} - Main color: ${item.mainColor}. Returning ${item.mainColor}`);
                    return item.mainColor;  //Function should return from here if match is found.
                }
            });
            logToPage(`No matches found for ${color}. Returning ${color}`)
            return color;    //No matches found
        }

        function writeToPage(text) { document.body.innerHTML += `<div class = "content"> ${text} </div>`; }
        function logToPage(text) { document.body.innerHTML += `<div class = "log"> ${text} </div >`; }

        const colorName = "Cyan";
        writeToPage(`Original Color: ${colorName}`)
        writeToPage(`Returned Value: ${substituteWithMainColor(colorName)}`);   // "Blue should be returned"
        .content {
            outline: 1px solid rgb(161, 189, 135);
            padding: 5px;
            margin: 5px;
            color: rgb(255, 127, 80);
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            font-size: 16px;
            font-weight: bold;
        }

        .log {
            outline: 1px solid #ccc;
            padding: 5px;
            margin: 5px;
            color: rgb(85, 91, 122);
            font-family: Verdana, Geneva, Tahoma, sans-serif;
            font-size: 12px;
        }

2
  • 3
    The return statement in the callback function of forEach returns from that callback only, and the value is ignored, it is not used anywhere. Commented May 24, 2021 at 9:33
  • Such a simple explanation - how could I not realize that it was returning from a callback? Appreciate your reply - would you like to make it a formal answer so that I can accept it? Commented May 24, 2021 at 9:35

1 Answer 1

3

A forEach is not the same an a normal for loop. You're essentially passing a function to be executed every loop, so your return acts in the scope of that function, not the loop.

It's a little like this:

for(let i = 0; i < 5; i++) {
    foo();
}

function foo() {
    // do something
    return true;
}

You're probably looking for something like find() (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)

substitutionArray.find(item => item.variations.includes(color)).mainColor;

Note that the return of the find it the item inside substitutionArray, so you have to extract the mainColor afterwards. If there's a chance that you won't find it, add a null check

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the detailed answer. Apart from understanding the error in my code, I was able to learn about and apply the find() method. Appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.