Можно ли опустить круглые скобки при создании объекта с помощью "нового" оператора?

Я видел объекты, созданные таким образом:

const obj = new Foo;

Но я думал, что круглые скобки не являются необязательными при создании объекта:

const obj = new Foo();

Является ли прежним способом создания объектов, действительных и определенных в стандарте ECMAScript? Существуют ли какие-либо различия между прежним способом создания объектов и более поздним? Один из них предпочтительнее другого?

Ответ 1

Цитата Дэвид Фланаган 1:

В качестве специального случая, только для оператора new, JavaScript упрощает грамматику, позволяя исключить круглую скобку, если в вызове функции нет аргументов. Вот несколько примеров с помощью оператора new:

o = new Object;  // Optional parenthesis omitted here
d = new Date();  

...

Лично я всегда использую круглые скобки, даже если конструктор не принимает аргументов.

Кроме того, JSLint может повредить ваши чувства, если вы опустите скобки. Он сообщает Missing '()' invoking a constructor, и, похоже, нет возможности для инструмента переносить опустошение в скобках.


1 Дэвид Фланаган: JavaScript: окончательное руководство: 4-е издание (стр. 75)

Ответ 2

Между ними существуют различия:

  • new Date().toString() отлично работает и возвращает текущую дату
  • new Date.toString() throws "TypeError: Date.toString не является конструктором"

Это происходит потому, что new Date() и new Date имеют другой приоритет. Согласно MDN, часть интересующей нас таблицы приоритетов JavaScript выглядит так:

╔════════════╦═════════════════════════════╦═══════════════╦═════════════╗
║ 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 …       ║
╚════════════╩═════════════════════════════╩═══════════════╩═════════════╝

Из этой таблицы следует, что:

  1. new Foo() имеет более высокий приоритет, чем new Foo

    new Foo() имеет тот же приоритет, что и . оператор

    new Foo имеет на один уровень более низкий приоритет, чем . оператор

    new Date().toString() отлично работает, потому что он оценивает как (new Date()).toString()

    new Date.toString() throws "TypeError: Date.toString не является конструктором", потому что . имеет более высокий приоритет, чем new Date (и выше, чем "вызов функции"), и выражение оценивается как (new (Date.toString))()

    Та же логика может применяться к оператору … [ … ].

  2. new Foo имеет ассоциативность справа налево и для new Foo() ассоциативности new Foo() "неприменим. Я думаю, что на практике это не имеет никакого значения. Дополнительную информацию см. В этом вопросе SO


Один из них предпочтительнее другого?

Зная все это, можно предположить, что new Foo() является предпочтительным.

Ответ 3

Я не думаю, что есть какая-то разница, когда вы используете "новый" оператор. Будьте осторожны, чтобы войти в эту привычку, поскольку эти две строки кода НЕ совпадают:

var someVar = myFunc; // this assigns the function myFunc to someVar
var someOtherVar = myFunc(); // this executes myFunc and assigns the returned value to someOtherVar

Ответ 4

Если у вас нет аргументов для передачи, скобки необязательны. Опущение их - это просто синтаксический сахар.

Ответ 5

https://people.mozilla.org/~jorendorff/es6-draft.html#sec-new-operator-runtime-semantics-evaluation

Вот часть спецификации ES6, которая определяет, как работают два варианта. Вариант без круглых скобок пропускает пустой список аргументов.

Интересно, что две формы имеют разные грамматические значения. Это происходит, когда вы пытаетесь получить доступ к члену результата.

new Array.length // fails because Array.length is the number 1, not a constructor
new Array().length // 0

Ответ 6

Нет никакой разницы между ними.