เราสามารถละเว้นวงเล็บเมื่อสร้างวัตถุโดยใช้ตัวดำเนินการ“ ใหม่” ได้หรือไม่?


229

ฉันเคยเห็นวัตถุที่ถูกสร้างขึ้นด้วยวิธีนี้:

const obj = new Foo;

แต่ฉันคิดว่าวงเล็บไม่ได้เป็นตัวเลือกเมื่อสร้างวัตถุ:

const obj = new Foo();

วิธีการสร้างวัตถุในอดีตนั้นใช้ได้และถูกกำหนดในมาตรฐาน ECMAScript หรือไม่? มีความแตกต่างระหว่างวิธีการสร้างวัตถุในอดีตหรือในภายหลังหรือไม่? เป็นที่ต้องการมากกว่าหนึ่งอื่น ๆ ?



อ้างอิง Updated: 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 David Flanagan: JavaScript the Definitive Guide: 4th Edition (หน้า 75)


6
ทำไม JSLint สนับสนุนให้ใช้วงเล็บ?
— Randomblue

11
ฉันคิดว่ามันถือว่ามีความสอดคล้องกันมากกว่านี้
— Daniel Vassallo

12
ฉันคิดว่ามันน่าสนใจที่จะเห็นว่าผู้พัฒนาจาวาสคริปต์หลายคนใช้วงเล็บเพราะ "เครื่องมือ (JSLint) บอกให้พวกเขาทำ" โดยเฉพาะอย่างยิ่งเมื่อพิจารณาจากตัวอย่างบนdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Guide / …จาก "คนที่ประดิษฐ์ภาษา <expletive>" ไม่ใช้วงเล็บใด ๆ บนnew Classสำหรับตัวสร้างแบบไม่มีพารามิเตอร์ หากยังไม่สามารถสะกด 'ดื้อดึง' ผมไม่ทราบว่าสิ่งที่ไม่ ...
— แอ๊

52
@ack มันจะแปลกที่จะไม่เห็นนักประดิษฐ์ของภาษาแสดงคุณลักษณะบางอย่างของภาษาของพวกเขา (ในกรณีนี้ตัวเลือกที่จะไม่ใส่วงเล็บในตัวสร้าง) หากพวกเขาไม่ได้เพิ่มคุณสมบัตินี้เราจะไม่ถามว่าควรจะใช้คุณลักษณะนี้ตั้งแต่แรกหรือไม่ เหตุผลการปฏิบัติสำหรับการไม่ได้ใช้มันอย่างนี้จะไม่เทียบเท่ากับnew Object.func() new Object().func()การรวมวงเล็บไว้เสมอความเป็นไปได้ในการทำผิดพลาดจะถูกกำจัด
— nmclean

2
(new Object).func()หากคุณต้องการที่จะกำจัดความเป็นไปได้ของการทำผิดพลาดที่คุณควรใช้ที่ แต่ฉันคิดว่าการใช้วงเล็บพิเศษและเครื่องหมายเท่ากับพิเศษอย่างเช่นเมื่อ==เทียบกับ===ข้ออ้างที่ไม่ดีสำหรับการไม่เรียนรู้ภาษาของคุณ
— Jean Vincent

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(และสูงกว่า "การเรียกใช้ฟังก์ชัน") และการแสดงออกจะประเมินว่า(new (Date.toString))()

    ตรรกะเดียวกันสามารถนำไปใช้กับ… [ … ]ผู้ประกอบการ

  2. new Fooมีการเชื่อมโยงจากขวาไปซ้ายและสำหรับnew Foo()"การเชื่อมโยง" ไม่สามารถใช้ได้ ฉันคิดว่าในทางปฏิบัติมันไม่ได้สร้างความแตกต่างเลย สำหรับข้อมูลเพิ่มเติมดูคำถาม SO นี้


เป็นที่ต้องการมากกว่าหนึ่งอื่น ๆ ?

เมื่อรู้ทุกอย่างแล้วสามารถสันนิษฐานได้ว่าnew Foo()เป็นที่ต้องการ


4
ในที่สุดคนที่ตอบคำถามและชี้ให้เห็นถึงความแตกต่างที่ลึกซึ้ง!
— gcampbell

ว้าวขอบคุณ. ทำให้ฉันนึกถึงภาษาอื่นen.wikipedia.org/wiki/Brainfuck
— John Henckel

ดีอธิบายข้อเสนอว่าเหตุผลที่ควรเป็นที่ต้องการมากกว่าnew Foo() new Fooคำตอบที่ดีที่สุด
— CodeLama

คำตอบที่ยอดเยี่ยมตารางนำหน้าและคำอธิบายประกอบทำให้ชัดเจนอย่างสมบูรณ์ ดีใจที่คุณอธิบายวิธีการที่ทำให้มัน alright การเขียนเช่นเดียวกับnew Object().something() (new Object()).something()
— LittleTiger

1
คำอธิบายที่ดี แต่ฉันไม่เห็นด้วยกับข้อสรุปและยังคิดว่าการใช้วงเล็บไม่เป็นไรถ้าคุณรู้ภาษาของคุณ BTW ถ้าคุณไม่ทราบว่ามีความสำคัญ JS คุณยังสามารถใช้การนับตัวอักษรเดียวกันและชัดเจนกว่า(new Date).toString() new Date().toString
— Jean Vincent

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
— Thomas Eding

ฉันจะบอกว่าเพิ่มพวกเขาหากพวกเขาไม่จำเป็นต้องมีน้ำตาลประโยค :)
— 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]] บน Constructor โดยไม่มีอาร์กิวเมนต์ (นั่นคือรายการอาร์กิวเมนต์ว่าง)"
— Benjamin Gruenbaum

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.