ตำแหน่งของวงเล็บสำหรับการเรียกใช้ฟังก์ชัน JavaScript ที่ไม่ระบุตัวตนโดยอัตโนมัติ?


107

ฉันเพิ่งเปรียบเทียบเวอร์ชันปัจจุบันของjson2.jsกับเวอร์ชันที่ฉันมีในโปรเจ็กต์ของฉันและสังเกตเห็นความแตกต่างในการสร้างนิพจน์ฟังก์ชันและดำเนินการด้วยตนเอง

รหัสที่ใช้ในการปิดฟังก์ชันนิรนามในวงเล็บแล้วเรียกใช้งาน

(function () {
  // code here
})();

แต่ตอนนี้มันรวมฟังก์ชันที่เรียกใช้งานอัตโนมัติไว้ในวงเล็บ

(function () {
  // code here
}());

มีความคิดเห็นโดย CMS ในคำตอบที่ยอมรับของไวยากรณ์ฟังก์ชันที่ไม่ระบุชื่อที่ห่อหุ้มของExplain JavaScriptว่า "ทั้งคู่: (function(){})();และ(function(){}());ถูกต้อง"

ฉันสงสัยว่าความแตกต่างคืออะไร? อดีตใช้หน่วยความจำโดยทิ้งฟังก์ชันทั่วโลกที่ไม่ระบุตัวตนหรือไม่? วงเล็บควรอยู่ที่ไหน?




1
อ่านเพิ่มเติมเกี่ยวกับวัตถุประสงค์ของโครงสร้างนี้หรือตรวจสอบคำอธิบาย ( ทางเทคนิค ) (ดูที่นี่ ) เหตุใดจึงจำเป็นต้องมีวงเล็บโปรดดูคำถามนี้
Bergi

คำตอบ:


66

พวกเขาแทบจะเหมือนกัน

แรกจะล้อมวงเล็บรอบฟังก์ชันเพื่อให้เป็นนิพจน์ที่ถูกต้องและเรียกใช้ ไม่ได้กำหนดผลลัพธ์ของนิพจน์

ฟังก์ชันที่สองเรียกใช้ฟังก์ชันและวงเล็บรอบการเรียกใช้อัตโนมัติทำให้เป็นนิพจน์ที่ถูกต้อง นอกจากนี้ยังประเมินไม่ได้กำหนด

ฉันไม่คิดว่าจะมีวิธีการที่ "ถูกต้อง" เนื่องจากผลลัพธ์ของนิพจน์นั้นเหมือนกัน

> function(){}()
SyntaxError: Unexpected token (
> (function(){})()
undefined
> (function(){return 'foo'})()
"foo"
> (function(){ return 'foo'}())
"foo"

8
JSLint ต้องการ "(function () {} ());". JSLint กล่าวว่า "ย้ายคำเรียกไปยัง parens ที่มีฟังก์ชัน"
XP1

27
ที่จริงคุณไม่ได้ จำกัด อยู่ที่ทั้งสองคุณสามารถใช้เพียงเกี่ยวกับอะไรที่ทำให้คอมไพเลอร์ตระหนักถึงหน้าที่เป็นส่วนหนึ่งของการแสดงออกและไม่คำสั่งเช่นหรือ+function(){}() !function(){}()
Tgr

49
@ XP1: JSLint ต้องการหลายสิ่งที่เฉพาะเจาะจงกับสไตล์ของ Crockford แทนที่จะเป็นแก่นสาร นี่คือหนึ่งในนั้น
TJ Crowder

@TJCrowder. คุณจะแนะนำอะไร? jQuery ใช้สไตล์แรกและ Crockford ใช้แบบที่สอง
Teej

4
@ThorpeObazee: มันไม่สำคัญจริงๆทำอะไรก็ได้ที่คุณต้องการ ผมอยากแนะนำให้กับบางส่วนของคนที่เกินธรรมดามากขึ้น ( -function(){}();, !function(){}();และพื้นประกอบการอื่น ๆ ก่อนที่จะfunctionยังทำงาน แต่ฉันติดกับรุ่นใช้ parens) ฉันเห็นเป็นครั้งแรกมากขึ้นกว่าที่ฉันเห็นที่สองและก็ตั้งค่าของฉัน; มันก็สมเหตุสมผลสำหรับฉันเช่นกัน แต่นั่นก็เป็นเรื่องส่วนตัว FWIW: jsbin.com/ejaqow
TJ Crowder

13

ในกรณีนั้นไม่สำคัญ คุณกำลังเรียกใช้นิพจน์ที่แก้ไขฟังก์ชันในนิยามแรกและกำหนดและเรียกใช้ฟังก์ชันในตัวอย่างที่สองทันที มีความคล้ายคลึงกันเนื่องจากนิพจน์ฟังก์ชันในตัวอย่างแรกเป็นเพียงนิยามฟังก์ชัน

มีกรณีอื่น ๆ ที่เป็นประโยชน์อย่างชัดเจนสำหรับการเรียกใช้นิพจน์ที่แก้ไขฟังก์ชัน:

(foo || bar)()

3
เพื่อความกระจ่างแก่ผู้อ่านคนอื่น ๆ (ส่วนใหญ่เป็นเพราะฉันไม่เข้าใจในตอนแรกตัวเอง :)) foo และ / หรือ bar ต้องเท่ากับฟังก์ชันบางอย่างอยู่แล้ว (เช่นfoo = function(){alert('hi');}ถ้าไม่ใช่ฟังก์ชันข้อผิดพลาดจะถูกโยนทิ้ง
Alexander Bird

3
@AlexanderBird คำชี้แจงเพิ่มเติม - นอกจากนี้ยังจะทำให้เกิดข้อผิดพลาดหากfooเป็น "จริง" แต่ไม่ใช่ฟังก์ชัน
JLRishe

9

ไม่มีความแตกต่างนอกเหนือจากไวยากรณ์

เกี่ยวกับความกังวลของคุณเกี่ยวกับวิธีที่สองในการทำ:

พิจารณา:

(function namedfunc () { ... }())

namedfuncจะยังคงไม่อยู่ในขอบเขตสากลแม้ว่าคุณจะระบุชื่อก็ตาม เช่นเดียวกับฟังก์ชันที่ไม่ระบุชื่อ วิธีเดียวที่จะทำให้มันอยู่ในขอบเขตนั้นคือการกำหนดให้กับตัวแปรภายใน parens

((namedfunc = function namedfunc () { ... })())

ไม่จำเป็นต้องใช้ parens ด้านนอก:

(namedfunc = function namedfunc () { ... })()

แต่คุณไม่ต้องการคำประกาศระดับโลกนั้นอีกแล้วใช่ไหม

ดังนั้นมันจึงเดือดถึง:

(function namedfunc () { ... })()

และคุณสามารถลดได้มากขึ้น: ชื่อนี้ไม่จำเป็นเนื่องจากจะไม่ถูกใช้ (เว้นแต่ฟังก์ชันของคุณจะเรียกซ้ำ .. และถึงแม้คุณจะใช้arguments.callee)

(function () { ... })()

นั่นคือวิธีที่ฉันคิด (อาจจะไม่ถูกต้องฉันยังไม่ได้อ่านข้อกำหนด ECMAScript) หวังว่าจะช่วยได้


โปรดทราบว่าarguments.calleeเลิกใช้แล้วตั้งแต่ ES5 (และห้ามใช้ในโหมดเข้มงวด)
nyuszika7h

"parens ด้านนอกไม่จำเป็น:" - ฉันคิดว่ามันป้องกันข้อผิดพลาดเมื่อไฟล์ถูกต่อกันมิฉะนั้นคุณจะต้องมี! หรือบางสิ่งบางอย่าง.
Jimmyt1988

-3

ความแตกต่างเกิดขึ้นเพราะ Douglas Crockford ไม่ชอบสไตล์แรกสำหรับIIFEs ! (seriuosly) อย่างที่เห็นในวิดีโอนี้ !! .

เหตุผลเดียวสำหรับการมีอยู่ของการตัดพิเศษ(){ในทั้งสองสไตล์} คือการช่วยสร้างส่วนของรหัสฟังก์ชันนิพจน์เนื่องจากการประกาศฟังก์ชันไม่สามารถเรียกใช้ได้ทันที บางสคริปต์ / ลดขนาด-ERS เพียงแค่ใช้+, !, -และ~แทนวงเล็บเกินไป แบบนี้:

+function() {  
    var foo = 'bar';  
}();

!function() {  
    var foo = 'bar';  
}();

-function() {  
    var foo = 'bar';  
}();

~function() {  
    var foo = 'bar';  
}();

และทั้งหมดนี้เหมือนกับทางเลือกอื่นของคุณทุกประการ การเลือกระหว่างกรณีเหล่านี้เป็นเรื่องของคุณเองและไม่สร้างความแตกต่าง {คนที่มี()การผลิต1 ไบต์ไฟล์ขนาดใหญ่ ;-)}

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