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

229

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

const obj = new Foo;

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

const obj = new Foo();

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

Бехранг Саидзаде
источник
Обновленная ссылка: ECMAScript 2017 § 12.3.3 Новый Opertator .
RobG
TL; DR: Остерегайтесь того, что new a.b()отличается от того new a().b(), что в первом случае a.bк нему обращаются первыми, тогда как во втором случае сначала создается новое a.
Андрей

Ответы:

238

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

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

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

...

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

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


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

Даниэль Вассалло
источник
6
Почему JSLint поощряет использование скобок?
Randomblue
11
Я думаю, это просто считается более последовательным.
Даниэль Вассалло
12
Мне интересно видеть, что многие разработчики JavaScript используют скобки просто потому, что «инструмент (JSLint) сказал им сделать это», особенно учитывая, что примеры на developer.mozilla.org/en-US/docs/Web/JavaScript/Guide /… От «парней, которые изобрели язык <expletive>» не используют круглые скобки new Classдля конструкторов без параметров. Если это не означает «самоуверенный», я не знаю, что значит ...
Ack
52
@ack Хорошо, было бы странно не видеть изобретателей языка, демонстрирующих некоторые особенности их языка (в этом случае, опцию опускать скобки в конструкторах). Если бы они не добавили эту функцию, мы бы не спросили, следует ли ее использовать в первую очередь. Практическая причина не использовать его заключается в следующем: new Object.func()НЕ эквивалентно new Object().func(). Всегда включая круглые скобки, исключается возможность совершения этой ошибки.
nmclean
2
Если вы хотите исключить возможность совершения ошибки, вам следует воспользоваться (new Object).func(). Но я считаю, что использование лишних скобок и лишних знаков равенства, как в случае с ==vs ===, является плохим оправданием для того, чтобы не изучать ваш язык.
Жан Винсент
78

Есть различия между ними:

  • new Date().toString() работает отлично и возвращает текущую дату
  • new Date.toString()бросает « Ошибка типа: 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()выдает « TypeError: Date.toString не является конструктором », поскольку .имеет более высокий приоритет, чем new Date(и выше, чем «вызов функции»), и выражение оценивается как(new (Date.toString))()

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

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


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

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

traxium
источник
4
Наконец, кто-то, кто действительно отвечает на вопрос и указывает на тонкую разницу!
Gcampbell
Вау, спасибо. напоминает мне о другом языке en.wikipedia.org/wiki/Brainfuck
Джон Хенкель
Хорошо объяснил, предлагает именно ту причину, почему new Foo()следует отдать предпочтение new Foo. Лучший ответ на данный момент.
CodeLama
Потрясающий ответ, таблица приоритетов и сопроводительное объяснение делают его совершенно понятным. Рад, что вы объяснили, как это позволяет писать, new Object().something()а также (new Object()).something().
LittleTiger
1
Отличное объяснение, но я не согласен с выводом и все же думаю, что не использовать скобки - это нормально, если вы знаете свой язык. Кстати, если вы не знаете приоритет JS, вы также можете использовать то (new Date).toString()же количество символов и более явный, чем new Date().toString.
Жан Винсент
14

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

var someVar = myFunc; // this assigns the function myFunc to someVar
var someOtherVar = myFunc(); // this executes myFunc and assigns the returned value to someOtherVar
jbabey
источник
1
Еще более проблематично, если вы не используете точки с запятой. ;-)
RobG
13

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

мистифицировать
источник
8
Я бы сказал, синтаксическая соль, но мммм.
Томас
Я бы сказал, добавление их, если они не нужны, является синтаксическим сахаром. :)
Cozzbie
8

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
гость
источник
Он хорошо определен и в ES5, и в ES3 - «Вернуть результат вызова внутреннего метода [[Construct]] для конструктора, не предоставляя аргументов (то есть пустой список аргументов)».
Бенджамин Грюнбаум
3

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

Иван
источник