ภาษาอื่นที่ไม่ใช่ JavaScript มีความแตกต่างระหว่างตำแหน่งเริ่มต้นของวงเล็บปีกกา (บรรทัดเดียวกันและบรรทัดถัดไป) หรือไม่


91

วันนี้ขณะที่ฉันสุ่มอ่านหนังสือ O'Reilly รูปแบบ JavaScript ฉันพบสิ่งที่น่าสนใจอย่างหนึ่ง (หน้า 27 สำหรับการอ้างอิง)

ใน Javascript ในบางกรณีอาจมีความแตกต่างหากตำแหน่งเริ่มต้นของวงเล็บปีกกาแตกต่างกัน

function test_function1() {
    return
    {
        name: 'rajat'
    };
}

var obj = test_function1();
alert(obj);  //Shows "undefined"

ในขณะที่

function test_function2() {
    return {
        name: 'rajat'
    };
}

var obj = test_function2();
alert(obj); //Shows object

การสาธิต JSfiddle

ภาษาอื่น ๆ มีพฤติกรรมเช่นนี้หรือไม่? ถ้าเป็นเช่นนั้นฉันจะต้องเปลี่ยนนิสัยของฉันอย่างแน่นอน .. :)

ฉันกังวลเกี่ยวกับ PHP, C, C ++, Java และ Ruby เป็นหลัก


1
ทำซ้ำใน Chrome และ IE9 จับได้ดี: P
gideon

4
ความไวของพื้นที่สีขาวสามารถทำงานได้ --- ดู python หรือ line mode fortran --- แต่ความไวของพื้นที่สีขาวที่ละเอียดอ่อนเป็นผลงานของปีศาจ แก! มันแย่พอ ๆ กับ make!
dmckee --- อดีตผู้ดูแลลูกแมว

น่าประทับใจขนาดนี้! พบดี!
CheckRaise

ตอนนี้ฉันต้องการทราบว่าเหตุใดจาวาสคริปต์จึงทำงานในลักษณะนี้
CheckRaise

4
@CheckRaise: ฉันสรุปกฎที่นี่: blogs.msdn.com/b/ericlippert/archive/2004/02/02/…
Eric Lippert

คำตอบ:


53

ภาษาใด ๆที่ไม่ขึ้นอยู่กับอัฒภาค (แต่ขึ้นบรรทัดใหม่แทน) เพื่อคั่นข้อความที่อาจทำให้เกิดสิ่งนี้ได้ พิจารณาPython :

>>> def foo():
...   return
...   { 1: 2 }
... 
>>> def bar():
...   return { 1: 2 }
... 
>>> foo()
>>> bar()
{1: 2}

คุณอาจสร้างกรณีที่คล้ายกันในVisual Basic ได้แต่จากด้านบนของหัวฉันฉันคิดไม่ออกว่าเป็นอย่างไรเพราะ VB ค่อนข้างมีข้อ จำกัด ในการวางค่า แต่สิ่งต่อไปนี้ควรใช้งานได้เว้นแต่ตัววิเคราะห์แบบคงที่จะบ่นเกี่ยวกับโค้ดที่ไม่สามารถเข้าถึงได้:

Try
    Throw New Exception()
Catch ex As Exception
    Throw ex.GetBaseException()
End Try

' versus

Try
    Throw New Exception()
Catch ex As Exception
    Throw
    ex.GetBaseException()
End Try

จากภาษาที่คุณกล่าวถึงRubyมีคุณสมบัติเหมือนกัน PHP, C, C ++ และ Java ไม่ได้เป็นเพียงเพราะพวกเขาทิ้งขึ้นบรรทัดใหม่เป็นช่องว่างและต้องใช้อัฒภาคเพื่อคั่นงบ

นี่คือรหัสที่เทียบเท่าจากตัวอย่าง Python ใน Ruby:

>> def foo
>>   return { 1 => 2 }
>> end
=> nil
>> def bar
>>   return
>>   { 1 => 2 }
>> end
=> nil
>> foo
=> {1=>2}
>> bar
=> nil

2
ตัวอย่าง VB ของคุณไม่ค่อยตรงประเด็นเนื่องจาก VB ไม่อนุญาตให้คำสั่งขยายหลายบรรทัดเว้นแต่คุณจะใช้ลำดับความต่อเนื่องของบรรทัด "_"
ผี

2
ตกลงฉันถอนความคิดเห็นก่อนหน้านี้เพราะฉันเพิ่งดูข้อมูลจำเพาะมีบริบทบางอย่างที่ VB.NET รองรับการต่อเนื่องของบรรทัดโดยนัย ฉันสงสัยว่าโปรแกรมเมอร์ VB ที่มีประสบการณ์จะพิจารณาตัวอย่างนี้ว่า "gotcha" อย่างไรก็ตามเนื่องจากเห็นได้ชัดว่าThrowและex.GetBaseException()เป็นบรรทัดเชิงตรรกะแยกกัน โดยเฉพาะอย่างยิ่งเนื่องจากพื้นฐานในอดีตใช้เส้นเพื่อคั่นประโยคคำสั่ง "gotcha" จึงน่าจะเป็นสถานการณ์ที่โปรแกรมเมอร์คิดว่าเขาสร้างคำสั่งใหม่ในบรรทัดเชิงตรรกะใหม่ แต่ไม่ได้
ผี

@phoog ทรูไม่ใช่ gotcha อย่างแน่นอน
Konrad Rudolph

40

ตัวแปล JavaScript จะเพิ่ม;ที่ท้ายบรรทัดแต่ละบรรทัดโดยอัตโนมัติหากไม่พบ (มีข้อยกเว้นบางประการไม่เข้าไปที่นี่ :)

ดังนั้นโดยทั่วไปปัญหาไม่ได้สถานที่จัดฟัน (ซึ่งที่นี่เป็นตัวแทนที่แท้จริงของวัตถุไม่ได้การป้องกันรหัสเช่นในภาษาส่วนใหญ่) แต่นี้ 'คุณสมบัติ' เล็ก ๆ น้อย ๆ ว่ากองกำลังตัวอย่างแรกของคุณเพื่อ=>return ; undefinedคุณสามารถตรวจสอบการทำงานของในสเป็คreturn ES5

สำหรับภาษาอื่น ๆ ที่มีลักษณะการทำงานที่คล้ายกันตรวจสอบคำตอบของคอนราด


5
คำตอบที่ได้รับการโหวตสูง แต่ผิดจริงขออภัย คำอธิบายดี แต่โปรดแก้ไขข้อผิดพลาด
Konrad Rudolph

ส่วนที่เกี่ยวกับ JavaScript ไม่ผิดลักษณะการทำงานของมันเป็นเพราะการแทรกเซมิโคลอนซึ่งบังคับundefinedให้ส่งกลับ ฉันเขียนเกี่ยวกับภาษาอื่น ๆ ที่มีคำนำหน้าด้วยafaikดังนั้นจงใช้เกลือเม็ด :)
Alex Ciminian

5
แต่ไม่เป็นความจริงที่ JS แทรกอัฒภาค "ที่ท้ายแต่ละบรรทัด" "โดยมีข้อยกเว้นบางประการ" แต่ก็มักจะไม่ได้ใส่อัฒภาคและมีเพียงไม่กี่กรณีที่ไม่ นั่นเป็นสาเหตุที่ทำให้ gotchas มากมาย
ruakh

26

มากที่สุดอย่างแน่นอน. ภาษาการเขียนโปรแกรมgoของ Google มีลักษณะการทำงานที่คล้ายกันมาก (แม้ว่าจะมีลักษณะพิเศษที่แตกต่างกัน) ตามที่อธิบายไว้ที่นั่น:

ในความเป็นจริงสิ่งที่เกิดขึ้นคือภาษาที่เป็นทางการใช้อัฒภาคเช่นเดียวกับใน C หรือ Java แต่จะถูกแทรกโดยอัตโนมัติที่ท้ายบรรทัดทุกบรรทัดที่ดูเหมือนท้ายคำสั่ง คุณไม่จำเป็นต้องพิมพ์เอง

.. สแนป ...

วิธีนี้ทำให้โค้ดดูสะอาดตาไม่มีอัฒภาค สิ่งที่น่าประหลาดใจอย่างหนึ่งคือการใส่วงเล็บปีกกาเปิดของโครงสร้างเช่นคำสั่ง if ในบรรทัดเดียวกับ if นั้นเป็นสิ่งสำคัญ หากไม่เป็นเช่นนั้นมีสถานการณ์ที่อาจรวบรวมไม่ได้หรืออาจให้ผลลัพธ์ที่ไม่ถูกต้อง ภาษาบังคับให้รูปแบบรั้งไปบ้าง

ฉันคิดว่า Rob Pike แค่ต้องการข้ออ้างเพื่อต้องการ One True Brace Style


10
เจ๋งไม่รู้เรื่องนี้ :). โดยส่วนตัวแล้วฉันไม่คิดว่าการแทรกอัฒภาคอัตโนมัติเป็นความคิดที่ดี สามารถแนะนำจุดบกพร่องที่ละเอียดอ่อนซึ่งผู้ที่ไม่มีประสบการณ์กับภาษาจะมีช่วงเวลาที่ยากลำบากในการค้นหา หากคุณต้องการเขียนโค้ดอัฒภาคฉันชอบวิธี python มากกว่า
Alex Ciminian

แม้ภาษา @ Alex โดยไม่ต้องใด ๆอัฒภาค (VB) มีคุณสมบัตินี้ Python ก็เช่นกันซึ่งคุณชอบแม้ว่ามันจะจัดการสิ่งนี้เหมือนกับ JavaScript ก็ตาม
Konrad Rudolph

ฉันจะโหวตให้ยกเว้นว่าประโยคที่สองของคุณผิดมากจนทำให้ฉันอยากจะโหวตลงไป ฉันเดาว่าพวกเขายกเลิก ;-)
ruakh

1
@ruakh คุณหมายถึง "ไปไม่ตรงนี้" หรือคุณหมายถึงเรื่องตลกเกี่ยวกับปล้นหอก? ในกรณีก่อนหน้านี้ฉันสามารถอ้างถึง "ไปแสดงพฤติกรรมเดียวกัน" ในภายหลังฉันขอโทษถ้าอารมณ์ขันที่ง่อยของฉันทำให้ขุ่นเคือง;)
Dave

1
ฉันหมายถึง "Go ทำอย่างนี้" ข้อเสนอเดิมสำหรับการแทรกเซมิโคลอนของ Go มีความแตกต่างอย่างชัดเจนกับ JavaScript โดยอธิบายว่า "ข้อเสนอนี้อาจทำให้คุณนึกถึงกฎอัฒภาคที่เป็นทางเลือกของ JavaScript ซึ่งจะเพิ่มอัฒภาคเพื่อแก้ไขข้อผิดพลาดในการแยกวิเคราะห์ข้อเสนอ Go แตกต่างกันอย่างสิ้นเชิง" และนั่นคือ ค่อนข้างจริงในทุกระดับมันทำงานแตกต่างกันมีเอฟเฟกต์ที่แตกต่างกันและแทบจะไม่มี gotcha เลย (การบังคับใช้ OTBS ในขณะที่น่ารำคาญไม่ใช่ gotcha เนื่องจากเป็นข้อกำหนดที่สอดคล้องกันในรหัส Go ทั้งหมด)
ruakh

14

คำตอบสำหรับคำถามนั้นค่อนข้างง่าย ภาษาใด ๆ ที่มี "การแทรกอัฒภาคอัตโนมัติ" อาจมีปัญหาในบรรทัดนั้น ปัญหาเกี่ยวกับเรื่องนี้

return
{
     name: 'rajat'
};

.. คือเครื่องยนต์ js จะใส่เครื่องหมายอัฒภาคหลังreturn;คำสั่ง (และส่งกลับundefined) ตัวอย่างนี้เป็นเหตุผลที่ดีในการเปิดวงเล็บปีกกาทางด้านขวาเสมอและไม่ควรอยู่ทางด้านซ้ายด้วย เนื่องจากคุณสังเกตเห็นได้อย่างถูกต้องแล้วหากมีวงเล็บปีกกาอยู่ในบรรทัดเดียวกันล่ามจะสังเกตเห็นสิ่งนั้นและไม่สามารถแทรกอัฒภาคได้


6

FWIW, JSLintรายงานคำเตือนหลายคำด้วยไวยากรณ์นั้น:

$ jslint -stdin
function foo(){
  return
  { x: "y" };
}
^D
(3): lint warning: unexpected end of line; it is ambiguous whether these lines are part of the same statement
  return
........^

(3): lint warning: missing semicolon
  { x: "y" };
..^

(3): lint warning: unreachable code
  { x: "y" };
..^

(3): lint warning: meaningless block; curly braces have no impact
  { x: "y" };
..^

(3): lint warning: use of label
  { x: "y" };
.....^

(3): lint warning: missing semicolon
  { x: "y" };
...........^

(3): lint warning: empty statement or extra semicolon
  { x: "y" };
............^


0 error(s), 7 warning(s)

1

ภาษาแรกที่ฉันเจอสิ่งนี้คือ awk (ซึ่งมีส่วนแบ่งของไวยากรณ์ "oddities" เซมิโคลอนที่เป็นทางเลือกการต่อสตริงโดยใช้ช่องว่างเท่านั้นและอื่น ๆ ... ) ฉันคิดว่านักออกแบบ DTrace ซึ่งใช้ไวยากรณ์ D อย่างหลวม ๆ ใน awk มีความรู้สึกเพียงพอที่จะไม่คัดลอกคุณสมบัติเหล่านี้ แต่ฉันจำไม่ได้ว่าอยู่ด้านบนสุดของหัว ตัวอย่างง่ายๆ (การนับจำนวนแท็ก ENTITY ใน DTD จาก Mac ของฉัน):

$ cat printEntities.awk 
# This prints all lines where the string ENTITY occurs
/ENTITY/ {
  print $0
}
$ awk -f printEntities.awk < /usr/share/texinfo/texinfo.dtd | wc -l
     119

หากสคริปต์เล็ก ๆ นี้ถูกเขียนขึ้นโดยใช้วงเล็บปีกกาบนบรรทัดของตัวเองสิ่งนี้จะเกิดขึ้น:

$ cat printAll.awk 
# Because of the brace placement, the print statement will be executed
# for all lines in the input file
# Lines containing the string ENTITY will be printed twice,
# because print is the default action, if no other action is specified
/ENTITY/
{ 
   print $0 
}
$ awk -f printAll.awk < /usr/share/texinfo/texinfo.dtd | wc -l
     603
$ /bin/cat < /usr/share/texinfo/texinfo.dtd | wc -l
     484
$ 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.