Czy możemy pominąć nawiasy podczas tworzenia obiektu za pomocą operatora „new”?

229

Widziałem obiekty tworzone w ten sposób:

const obj = new Foo;

Ale myślałem, że nawiasy nie są opcjonalne podczas tworzenia obiektu:

const obj = new Foo();

Czy poprzedni sposób tworzenia obiektów jest prawidłowy i zdefiniowany w standardzie ECMAScript? Czy są jakieś różnice między pierwszym sposobem tworzenia obiektów a późniejszym? Czy jedno jest lepsze od drugiego?

Behrang Saeedzadeh
źródło
Zaktualizowany numer referencyjny: ECMAScript 2017 §12.3.3 Nowy operator .
RobG
TL, DR: Uwaga który new a.b()różni się od new a().b(), na tym, że w pierwszym przypadku, a.bjest po raz pierwszy dostępne, przy czym w tym ostatnim przypadku, nowa asię utworzyć.
Andrew

Odpowiedzi:

238

Cytując Davida Flanagana 1 :

Jako szczególny przypadek, tylko dla newoperatora, JavaScript upraszcza gramatykę, umożliwiając pominięcie nawiasu, jeśli w wywołaniu funkcji nie ma argumentów. Oto kilka przykładów za pomocą newoperatora:

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

...

Osobiście zawsze używam nawiasu, nawet jeśli konstruktor nie przyjmuje żadnych argumentów.

Ponadto JSLint może zranić twoje uczucia, jeśli pominiesz nawias. Raportuje Missing '()' invoking a constructor, i wydaje się, że narzędzie nie toleruje pominięcia nawiasów.


1 David Flanagan: JavaScript Przewodnik definitywny: wydanie czwarte (strona 75)

Daniel Vassallo
źródło
6
Dlaczego JSLint zachęca do używania nawiasów?
Randomblue,
11
Myślę, że jest to po prostu uważane za bardziej spójne.
Daniel Vassallo,
12
Interesujące jest dla mnie to, że wielu programistów JavaScript używa nawiasów tylko dlatego, że „narzędzie (JSLint) kazało im to zrobić”, szczególnie biorąc pod uwagę, że przykłady na developer.mozilla.org/en-US/docs/Web/JavaScript/Guide /… Od „facetów, którzy wymyślili język <wybórczy>”, nie używają nawiasów new Classdla konstruktorów bez parametrów. Jeśli to nie oznacza „opiniotwórczego”, nie wiem, co to znaczy
ack
52
@ack Dobrze byłoby dziwne nie widzieć wynalazcy języku za zaprezentować pewne cechy ich języka (w tym przypadku opcja pominąć nawiasy na konstruktorów). Gdyby nie dodali tej funkcji, nie pytalibyśmy, czy należy jej użyć. Praktycznym powodem nieużywania go jest: new Object.func()NIE jest ono równoważne z new Object().func(). Przez zawsze dołączanie nawiasów eliminuje się możliwość popełnienia tego błędu.
nmclean
2
Jeśli chcesz wyeliminować możliwość popełnienia błędu, powinieneś użyć (new Object).func(). Ale należy rozważyć użycie dodatkowych nawiasów i dodatkowe znaki równości, jak w ==vs ===, zły pretekstem do nauki języka.
Jean Vincent
78

Istnieją dwie różnice między nimi:

  • new Date().toString() działa idealnie i zwraca bieżącą datę
  • new Date.toString()zgłasza „ TypeError: Date.toString nie jest konstruktorem

Zdarza się, bo new Date()i new Datemają różne pierwszeństwo. Według MDN część tabeli priorytetów operatora JavaScript, którą jesteśmy zainteresowani, wygląda następująco:

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

Z tej tabeli wynika, że:

  1. new Foo() ma wyższy priorytet niż new Foo

    new Foo()ma taki sam priorytet jak .operator

    new Fooma o jeden poziom niższy priorytet niż .operator

    new Date().toString() działa idealnie, ponieważ ocenia jako (new Date()).toString()

    new Date.toString()zgłasza „ TypeError: Date.toString nie jest konstruktorem ”, ponieważ .ma wyższy priorytet niż new Date(i wyższy niż „wywołanie funkcji”), a wyrażenie ma wartość(new (Date.toString))()

    Tę samą logikę można zastosować do … [ … ]operatora.

  2. new Fooma skojarzenie od prawej do lewej, a określenie new Foo()„skojarzenie” nie ma zastosowania. Myślę, że w praktyce nie robi to żadnej różnicy. Aby uzyskać dodatkowe informacje, zobacz to SO pytanie


Czy jedno jest lepsze od drugiego?

Wiedząc o tym wszystkim, można założyć, że new Foo()jest to preferowane.

traxium
źródło
4
Wreszcie, ktoś, kto faktycznie odpowiada na pytanie i zwraca uwagę na subtelną różnicę!
gcampbell
wow, dzięki. przypomina mi inny język en.wikipedia.org/wiki/Brainfuck
John Henckel
Dobrze wyjaśnione, oferuje dokładnie powód, dla którego new Foo()należy preferować new Foo. Najlepsza jak dotąd odpowiedź.
CodeLama,
Niesamowita odpowiedź, tabela pierwszeństwa i towarzyszące jej wyjaśnienie wyjaśniają wszystko. Cieszę się wyjaśnić, jak to sprawia, że w porządku napisać new Object().something()jak również (new Object()).something().
LittleTiger,
1
Świetne wyjaśnienie, ale nie zgadzam się z wnioskiem i nadal uważam, że nie używanie nawiasów jest w porządku, jeśli znasz swój język. BTW, jeśli nie znasz pierwszeństwa JS, możesz również użyć tej (new Date).toString()samej liczby znaków i bardziej jawnie niż new Date().toString.
Jean Vincent
14

Nie sądzę, aby istniała jakaś różnica, kiedy używasz „nowego” operatora. Zachowaj ostrożność przy wchodzeniu w ten nawyk, ponieważ te dwie linie kodu NIE są takie same:

var someVar = myFunc; // this assigns the function myFunc to someVar
var someOtherVar = myFunc(); // this executes myFunc and assigns the returned value to someOtherVar
jbabey
źródło
1
Jeszcze bardziej problematyczne, jeśli masz w zwyczaju pomijać średniki. ;-)
RobG
13

Jeśli nie masz argumentów do przekazania, nawiasy są opcjonalne. Pominięcie ich to tylko cukier składniowy.

Josh
źródło
8
Powiedziałbym, że sól syntaktyczna, ale ymmv.
Thomas Eding,
Powiedziałbym, że dodanie ich, jeśli nie są potrzebne, to cukier syntaktyczny. :)
Cozzbie
8

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

Oto część specyfikacji ES6, która określa sposób działania dwóch wariantów. Wariant bez nawiasów przekazuje pustą listę argumentów.

Co ciekawe, te dwie formy mają różne znaczenia gramatyczne. Pojawia się, gdy próbujesz uzyskać dostęp do członka wyniku.

new Array.length // fails because Array.length is the number 1, not a constructor
new Array().length // 0
Gość
źródło
Jest również dobrze zdefiniowany w ES5 i ES3 - „Zwraca wynik wywołania wewnętrznej metody [[Konstruuj]] na konstruktorze, nie podając żadnych argumentów (to znaczy pustej listy argumentów).”
Benjamin Gruenbaum
3

Nie ma między nimi żadnej różnicy.

Ivan
źródło