I have seen objects being created this way:
const obj = new Foo;
But I thought that the parentheses are not optional when creating an objec
There are differences between the two:
new Date().toString() works perfectly and returns the current datenew Date.toString() throws "TypeError: Date.toString is not a constructor"It happens because new Date() and new Date have different precedence. According to MDN the part of JavaScript operator precedence table we are interested in looks like:
╔════════════╦═════════════════════════════╦═══════════════╦═════════════╗
║ Precedence ║ Operator type ║ Associativity ║ Operators ║
╠════════════╬═════════════════════════════╬═══════════════╬═════════════╣
║ 18 ║ Member Access ║ left-to-right ║ … . … ║
║ ║ Computed Member Access ║ left-to-right ║ … [ … ] ║
║ ║ new (with argument list) ║ n/a ║ new … ( … ) ║
╠════════════╬═════════════════════════════╬═══════════════╬═════════════╣
║ 17 ║ Function Call ║ left-to-right ║ … ( … ) ║
║ ║ new (without argument list) ║ right-to-left ║ new … ║
╚════════════╩═════════════════════════════╩═══════════════╩═════════════╝
From this table follows that:
new Foo() has higher precedence than new Foo
new Foo() has the same precedence as . operator
new Foo has one level lower precedence than the . operator
new Date().toString() works perfectly because it evaluates as (new Date()).toString()
new Date.toString() throws "TypeError: Date.toString is not a constructor" because . has higher precedence than new Date (and higher then "Function Call") and the expression evaluates as (new (Date.toString))()
The same logic can be applied to … [ … ] operator.
new Foo has right-to-left associativity and for new Foo() "associativity" isn't applicable. I think in practice it doesn't make any difference. For additional information see this SO question
Is one preferred over the other?
Knowing all that, it can be assumed that new Foo() is preferred.