Bisakah kita menghilangkan tanda kurung ketika membuat objek menggunakan operator "baru"?

229

Saya telah melihat objek yang dibuat dengan cara ini:

const obj = new Foo;

Tetapi saya berpikir bahwa tanda kurung tidak opsional ketika membuat objek:

const obj = new Foo();

Apakah cara sebelumnya untuk membuat objek valid dan didefinisikan dalam standar ECMAScript? Apakah ada perbedaan antara cara sebelumnya membuat objek dan kemudian? Apakah yang satu lebih disukai daripada yang lain?

Behrang Saeedzadeh
sumber
Referensi yang diperbarui: ECMAScript 2017 §12.3.3 Opertator baru .
RobG
TL; DR: Waspadalah yang new a.b()berbeda dengan new a().b(), dalam hal itu, dalam kasus a.byang pertama, pertama kali diakses, sedangkan dalam kasus yang terakhir, yang baru adibuat terlebih dahulu.
Andrew

Jawaban:

238

Mengutip David Flanagan 1 :

Sebagai kasus khusus, untuk newoperator saja, JavaScript menyederhanakan tata bahasa dengan membiarkan tanda kurung dihilangkan jika tidak ada argumen dalam pemanggilan fungsi. Berikut ini beberapa contoh menggunakan newoperator:

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

...

Secara pribadi, saya selalu menggunakan tanda kurung, bahkan ketika konstruktor tidak mengambil argumen.

Selain itu, JSLint dapat melukai perasaan Anda jika Anda menghilangkan tanda kurung. Ini melaporkan Missing '()' invoking a constructor, dan sepertinya tidak ada pilihan untuk alat untuk mentolerir penghilangan kurung.


1 David Flanagan: JavaScript the Definitive Guide: Edisi ke-4 (halaman 75)

Daniel Vassallo
sumber
6
Mengapa JSLint mendorong penggunaan tanda kurung?
Randomblue
11
Saya kira itu hanya dianggap lebih konsisten.
Daniel Vassallo
12
Saya merasa menarik untuk melihat bahwa banyak pengembang JavaScript menggunakan tanda kurung hanya karena "alat (JSLint) menyuruh mereka melakukannya", terutama mengingat bahwa contoh pada developer.mozilla.org/en-US/docs/Web/JavaScript/Guide /… , Dari "orang-orang yang menemukan bahasa <expletive>" tidak menggunakan tanda kurung new Classuntuk konstruktor tanpa parameter. Jika ini tidak mengeja 'pendapat', saya tidak tahu apa yang ...
ack
52
@ack Yah, akan aneh untuk tidak melihat penemu bahasa memamerkan fitur tertentu dari bahasa mereka (dalam hal ini, opsi untuk menghilangkan tanda kurung pada konstruktor). Jika mereka tidak menambahkan fitur, kami tidak akan bertanya apakah itu harus digunakan. Alasan praktis untuk tidak menggunakannya adalah ini: new Object.func()TIDAK setara dengan new Object().func(). Dengan selalu menyertakan tanda kurung, kemungkinan membuat kesalahan ini dihilangkan.
nmclean
2
Jika Anda ingin menghilangkan kemungkinan melakukan kesalahan Anda harus menggunakan (new Object).func(). Tapi saya mempertimbangkan menggunakan tanda kurung tambahan dan tanda-tanda ekstra sama, seperti dalam ==vs ===, alasan buruk untuk tidak belajar bahasa Anda.
Jean Vincent
78

Ada perbedaan di antara keduanya:

  • new Date().toString() berfungsi dengan baik dan mengembalikan tanggal saat ini
  • new Date.toString()throws " TypeError: Date.toString bukan konstruktor "

Itu terjadi karena new Date()dan new Datememiliki prioritas yang berbeda. Menurut MDN bagian dari tabel prioritas operator JavaScript yang kami minati terlihat seperti:

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

Dari tabel ini berikut bahwa:

  1. new Foo() memiliki prioritas lebih tinggi daripada new Foo

    new Foo()memiliki prioritas yang sama dengan .operator

    new Foomemiliki prioritas satu tingkat lebih rendah daripada .operator

    new Date().toString() berfungsi dengan baik karena dievaluasi sebagai (new Date()).toString()

    new Date.toString()melempar " TypeError: Date.toString bukan konstruktor " karena .memiliki prioritas lebih tinggi daripada new Date(dan lebih tinggi dari "Function Call") dan ekspresi dievaluasi sebagai(new (Date.toString))()

    Logika yang sama dapat diterapkan ke … [ … ]operator.

  2. new Foomemiliki associativity kanan-ke-kiri dan untuk new Foo()"associativity" tidak berlaku. Saya pikir dalam praktiknya tidak ada bedanya. Untuk informasi tambahan, lihat pertanyaan SO ini


Apakah yang satu lebih disukai daripada yang lain?

Mengetahui semua itu, dapat diasumsikan new Foo()lebih disukai.

traxium
sumber
4
Akhirnya, seseorang yang benar-benar menjawab pertanyaan dan menunjukkan perbedaan yang halus!
gcampbell
Wow terima kasih. mengingatkan saya pada bahasa lain en.wikipedia.org/wiki/Brainfuck
John Henckel
Dijelaskan dengan baik, menawarkan alasan yang tepat mengapa new Foo()harus lebih disukai new Foo. Jawaban terbaik sejauh ini.
CodeLama
Jawaban yang luar biasa, tabel diutamakan dan penjelasan yang menyertainya membuatnya sangat jelas. Senang Anda menjelaskan bagaimana hal itu membuatnya baik untuk menulis new Object().something()juga (new Object()).something().
LittleTiger
1
Penjelasan yang bagus tapi saya tidak setuju dengan kesimpulan dan masih berpikir tidak menggunakan tanda kurung baik-baik saja jika Anda tahu bahasa Anda. BTW jika Anda tidak tahu prioritas JS, Anda juga bisa menggunakan (new Date).toString(), jumlah karakter yang sama, dan lebih eksplisit daripada new Date().toString.
Jean Vincent
14

Saya tidak berpikir ada perbedaan ketika Anda menggunakan operator "baru". Hati-hati dengan kebiasaan ini, karena dua baris kode ini TIDAK sama:

var someVar = myFunc; // this assigns the function myFunc to someVar
var someOtherVar = myFunc(); // this executes myFunc and assigns the returned value to someOtherVar
jaby
sumber
1
Bahkan lebih bermasalah jika Anda terbiasa menghilangkan tanda titik koma. ;-)
RobG
13

Jika Anda tidak memiliki argumen untuk diteruskan, tanda kurung opsional. Menghilangkan mereka hanyalah gula sintaksis.

Josh
sumber
8
Saya akan mengatakan garam sintaksis, tetapi ymmv.
Thomas Eding
Saya akan mengatakan menambahkan mereka jika mereka tidak diperlukan adalah gula sintaksis. :)
Cozzbie
8

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

Inilah bagian dari spesifikasi ES6 yang mendefinisikan bagaimana kedua varian beroperasi. Varian tanpa tanda kurung melewati daftar argumen kosong.

Menariknya, kedua bentuk tersebut memiliki makna tata bahasa yang berbeda. Ini muncul ketika Anda mencoba mengakses anggota hasil.

new Array.length // fails because Array.length is the number 1, not a constructor
new Array().length // 0
tamu
sumber
Itu didefinisikan dengan baik di ES5 dan ES3 juga - "Kembalikan hasil memanggil metode internal [[Bangun]] pada konstruktor, tidak memberikan argumen (yaitu, daftar argumen kosong)."
Benjamin Gruenbaum
3

Tidak ada perbedaan di antara keduanya.

Ivan
sumber