"{...} is not a function" although never called as a function

Viewed 153

If I create a JSON object immediately before an anonymous function call, I get TypeError: ({x:0, y:0}) is not a function in Firefox, or Uncaught TypeError: {(intermediate value)(intermediate value)} is not a function in Chrome.

However, I never called a as a function. Also, when I put a semicolon after the object definition, this error does not occur.

According to http://inimino.org/~inimino/blog/javascript_semicolons I don't see why I would, in theory, need a semicolon there. However, for some reason it is still required. Why?

let a = { x: 0, y: 0 }

(() => {
    console.log('test')
})()

4 Answers

As other's have said, the two statements are being read as a single, non-sensical statement. My peeve here is that no-one has properly answered why this happens here and not in other cases.

You quote the NPM style guide here: https://docs.npmjs.com/misc/coding-style.html It says

In front of a leading ( or [ at the start of the line. This prevents the expression from being interpreted as a function call or property access, respectively.

So your issue is because the second statement starts with ( or [, and this confuses the parser. In these cases a semi-colon is needed. Why would the parser be confused by ( or [? Because for instance { x: 0, y: 0}["x"] would be valid code. And the same for { x: 0, y: 0}(), it's perfectly valid, it will just crash. But the parser cannot know if it makes sense or not, it has to apply the same rules everywhere.

Note that the npm style guide then says to put the semi-colon on the line with the ( in cases like this. So you would write:

let a = { x: 0, y: 0 }

;(() => { // semi-colon at start of this line
    console.log('test')
})()

The reason for this is that if you were to put it after the first statement and later edit your code, you would re-introduce the problem. For instance end up like this:

let a = { x: 0, y: 0 };

let b = { x: 1, y: 1 }

(() => { // this will fail
    console.log('test')
})()

You haven't terminated your assignment to x, so the engine is seeing you call a function:

// Wrong:
let {x: 0, y:}()();

You should use semi-colon to terminate:

let a = { x: 0, y: 0 }; // terminate this line with a semi-colon ;

(() => {
    console.log('test')
})()

The reason why is, without the semi-colon, the two statements will be read as one, in turn making no sense.

Always use semicolon ,since Javascript compiler compile the code line by line from top to bottom ,so in your case it is interpreted as

let a = { x: 0, y: 0 } (() => { console.log('test') })()

and compiler is unable to determine where the line terminates and also the func is executed at the same time which makes no sense to the compiler. That's why you are getting TypeError as you mentioned.

To fix this use semicolon after defining your object like this

let a = { x: 0, y: 0 } ;
(() =>  console.log('test') )();

You can also remove curly braces to refactor your code (just a little advice) since your function is not returning any value (using es6 property).

Related