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;
}
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