Чи можемо ми пропустити круглі дужки під час створення об'єкта за допомогою «нового» оператора?


229

Я бачив об'єкти, створені таким чином:

const obj = new Foo;

Але я подумав, що круглі дужки не є обов’язковими при створенні об'єкта:

const obj = new Foo();

Чи вірний і визначений колишній спосіб створення об'єктів у стандарті ECMAScript? Чи є відмінності між колишнім способом створення об’єктів та пізнішим? Чи один віддає перевагу іншому?



Оновлена ​​довідка: ECMAScript 2017, §12.3.3 Новий оператор .
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(). Але я вважаю, що використання додаткових дужок та зайвих рівних знаків, як і в ==порівнянні ===, є поганим приводом для того, щоб не вивчити свою мову.
Жан Вінсент

78

Існують відмінності між цими двома:

  • new Date().toString() працює чудово і повертає поточну дату
  • new Date.toString()кидає " 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()кидає " TypeError: Date.toString не є конструктором ", оскільки .має перевагу вищеnew Date (і вище "Function Call"), а вираз оцінюється як(new (Date.toString))()

    Така ж логіка може бути застосована і до … [ … ]оператора.

  2. new Fooмає право-наліво асоціативність і для new Foo()"асоціативності" не застосовується. Я думаю, що на практиці це не має ніякого значення. Для отримання додаткової інформації дивіться це запитання щодо ТАК


Чи один віддає перевагу іншому?

Знаючи все це, можна припустити, що new Foo()перевагу.


4
Нарешті, хтось, хто насправді відповідає на питання, і вказує на тонку різницю!
gcampbell

вау, спасибі нагадує мені про іншу мову en.wikipedia.org/wiki/Brainfuck
Джон Генкель

Добре пояснено, пропонується саме причина, чому new Foo()слід віддавати перевагу new Foo. Найкраща відповідь поки що.
CodeLama

Дивовижна відповідь, таблиця пріоритету та супровідне пояснення це дає зрозуміти повністю. Радий , що ви пояснити , як це робить це добре для запису new Object().something(), а також (new Object()).something().
LittleTiger

1
Чудове пояснення, але я не погоджуюся з висновком і все ще думаю, що не використовувати дужки, це добре, якщо ви знаєте свою мову. BTW, якщо ви не знаєте пріоритету JS, ви також можете використовувати те (new Date).toString()саме число символів і більш чітке, ніж new Date().toString.
Жан Вінсент

14

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

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

1
Ще більш проблематично, якщо ви звикли пропускати крапки з комою. ;-)
RobG

13

Якщо у вас немає аргументів для передачі, дужки необов’язкові. Опускати їх - це просто синтаксичний цукор.


8
Я б сказав, синтаксична сіль, але ymmv.
Томас Едінг

Я б сказав, що додавання їх, якщо вони не потрібні, є синтаксичним цукром. :)
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]] на конструктор, не надаючи аргументів (тобто порожній список аргументів)."
Бенджамін Грюнбаум

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.