Fun Javascript surprise

Let’s say you’re messing around writing parsers and want to represent tokenized bits of text with this sort of JS object.

{
    tok:   STRING,        //token type (NUMBER, WORD, STRING, etc)
    value: "hello world"  //the parsed token
}

It’s possible to make them like this:

let tok = STRING;
let value = parseString();
return { tok: tok, value: value };

But JS has a shorter syntax for defining objects whos keys happen to match the variable names you’re assigning to them. Can save a bit of repetition and clutter this way:

let tok = STRING;
let value = parseString();
return { tok, value };

It might be nice to break it into its own function, too:

function token(tok, value) {
    return {tok, value};
}

return token(STRING, parseString()); //convenient

And what about an arrow function while we’re at it?

const token = (tok, value) => { tok, value };

return token(STRING, parseString()); //undefined

But this arrow function doesn’t work! It always returns undefined.

This is because the curly braces around the arrow function are now being parsed as delimiters for the body of the arrow function, instead of delimiters for an object literal. The body of the function is

tok, value

This is a valid JS expression; it’s the comma operator, which evaluates the left side, discards the result, and evaluates to the right side. And because the arrow function now uses curly braces, it’d require a return statement to return anything. And it doesn’t. So it returns undefined.

The fix is to add parenthesis so the braces on the right-hand side get parsed as an object literal instead of as function delimiters.

const token = (tok, value) => ({ tok, value });

Or expand it out.

const token = (tok, value) => { return { tok, value }; };

Another clue that something is amiss is that if you try to expand out the shorthand notation, you’ll get a parse error:

const token = (tok, value) => { tok: tok, value: value };
//                                 ^ Uncaught SyntaxError: unexpected token: ':'

Your syntax highlighter might be misleading you too!