JavaScript has a helper that adds semicolons, the little marks that end a line of code, wherever it thinks you forgot one. When it sees return alone at the end of a line, it decides you are finished and puts a semicolon right there. The object on the next line is never reached.
The curse
function getCat() {
return
{
name: "Mia"
};
}
console.log(getCat()); // prints: undefined
The function clearly returns an object with a name. Call it, and you get undefined, with no error and no warning.
What JavaScript does
The helper is called automatic semicolon insertion, or ASI. When a line ends and the code there could be read as a finished statement, JavaScript may add a semicolon for you.
return has a stricter rule. If a line break comes straight after return, JavaScript always ends the statement there. So the function above is read like this.
function getCat() {
return;
{
name: "Mia"
}
}
console.log(getCat()); // prints: undefined
A bare return; gives back undefined, and the lines below it never run. They don't even count as an object anymore. JavaScript reads the curly braces as a block of code with a label called name inside, which is still valid code. That is why there is no error to warn you.
The helper exists so tiny slips don't break whole programs, and most of the time it guesses right. After return, it guesses wrong.
How to break the curse
Put the opening curly brace on the same line as return.
function getCat() {
return {
name: "Mia"
};
}
console.log(getCat()); // prints: { name: 'Mia' }
Now the line doesn't end after return, so JavaScript keeps reading and returns the object. The same goes for any long value. If you want to spread it over several lines, start it on the return line, for example with return ( and the rest below.
Bonus twist: when no semicolon is added
Sometimes the helper does the opposite. It only adds a semicolon when the next line can't continue the current one. A line that starts with [ or ( can continue the line above, so JavaScript glues the two lines together.
const a = 1
[1, 2].forEach((n) => console.log(n));
JavaScript reads this as one long line, const a = 1[1, 2].forEach(...). That looks up a property on the number 1, gets undefined, and crashes with "TypeError: Cannot read properties of undefined (reading 'forEach')".
Watch out for lines that start with [, ( or a template literal. This is why many people end every finished line of code with a semicolon. Tools like Prettier and ESLint can add them for you, or warn you when a line could be glued to the one above.
Rule of thumb
Keep the curly brace on the same line as return, and end each finished line of code with a semicolon.
Pressing Enter right after return to make a long value look tidy. Start the value on the same line, with return { or return (, so JavaScript knows more is coming.
Check yourself
JavaScript adds a semicolon right after return because of the line break, so the function returns nothing, which is undefined.