JavaScript Array Map — Why is this console.log ignored?
This is a daily Javascript challenge from the CodeShot archive. Practice your knowledge of Unreachable Code After Return and improve your technical interview readiness.
const numbers = [1, 2, 3, 4]
const doubled = numbers.map(n => {
return n * 2
console.log(n)
})
console.log(doubled)
Detailed Explanation
Why This Question Matters
If you're just starting out with JavaScript, .map() feels like magic. You give it an array, you tell it what to do to each element, and boom—you get a new array back. It's a staple of modern JS development, especially if you're moving into React or Vue.
But there's a catch. Most bugs aren't caused by a lack of knowledge about the syntax; they're caused by a misunderstanding of how the engine actually executes the code. The snippet in this challenge is a classic "gotcha." It tests whether you actually understand how return works inside a function, or if you're just guessing based on what the code looks like.
Understanding the Code
Let's look at the snippet again:
At first glance, it looks fine. We have an array of numbers, we're mapping over them, we multiply by two, and we log the result. But if you run this, you'll notice something weird: the console.log(n) inside the map function never actually fires.
Here is what's happening under the hood.
The .map() method takes a callback function and runs it for every single item in the array. In this case, the callback is an arrow function. Inside that function, we have two lines of code. The first line is return n * 2.
In JavaScript, the return statement is the "exit door" of a function. The moment the engine hits a return, it stops everything else in that function and immediately hands the value back to whatever called it. It doesn't matter if there are ten more lines of code, a complex loop, or a console.log right underneath it. Once the function returns, it's done.
So, for every number in the array, JS calculates n * 2, returns that value to the new doubled array, and completely ignores the console.log(n) line. It's what we call unreachable code.
Finding the Correct Answer
The "bug" here isn't that the array isn't being doubled—it actually is. The bug is that the developer likely expected to see the numbers logged to the console while the mapping was happening, but they placed the log *after* the return statement.
To fix this, the console.log(n) needs to happen before the return.
The wrong way:
The right way:
If this were a multiple-choice question where Option B suggests moving the log above the return or removing the return to see the log (though removing the return would break the .map() functionality), that's why it's the winner. You cannot execute logic after a return statement in the same block.
Common Mistakes Developers Make
This is a rite of passage for junior devs. A few common traps I see:
1. The "Implicit Return" Confusion:
Arrow functions have a shorthand. If you remove the curly braces, the return is implicit.
const doubled = numbers.map(n => n * 2);
Beginners often try to add a console.log into this shorthand version and get confused when they can't figure out where to put the curly braces back in to make the log work.
2. Forgetting the Return Entirely:
I've seen plenty of developers write a .map() with curly braces but forget the return keyword.
In this case, the function returns
undefined for every element, and you end up with an array like [undefined, undefined, undefined, undefined].
3. Using .map() when they should use .forEach():
If you find yourself writing a .map() but you aren't actually using the returned array (you're just logging or updating a database), you're using the wrong tool. Use .forEach() for side effects and .map() for transforming data.
Real-World Usage
In a production environment, you'll rarely see a console.log inside a map, but you'll see this "unreachable code" logic error in more complex scenarios.
Imagine a function that validates a user's permissions. You might have a guard clause at the top:
If a developer accidentally puts a crucial piece of logic (like logging an audit trail or updating a timestamp) *after* a return statement, that logic simply disappears. It doesn't throw an error; it just never happens. That's why these "silent" bugs are the most dangerous.
Key Takeaways
- Return is final: Once a function hits return, it's over. Anything below it in the same block is dead code.
- Map is for transformation: Use .map() when you want a new array based on the old one.
- Watch your braces: If you use curly braces {} in an arrow function, you must explicitly use the return keyword.
- Debug wisely: If your console.log isn't showing up, check if it's sitting behind a return statement.
Why this matters
Understanding Unreachable Code After Return is crucial for passing technical interviews. In real-world applications, this concept often leads to subtle bugs if not handled correctly. For more details, you can always refer to the official MDN Documentation.