ใน JavaScript มันสร้างความแตกต่างหรือไม่ถ้าฉันเรียกใช้ฟังก์ชันด้วยวงเล็บ?


104

ฉันสังเกตเห็นความแตกต่างเมื่อเรียกใช้ฟังก์ชันโดยใช้วงเล็บว่างหรือไม่มีวงเล็บเลย อย่างไรก็ตามฉันไม่ได้ส่งผ่านข้อโต้แย้งใด ๆ ไปยังฟังก์ชันดังนั้นฉันจึงสงสัยว่าความแตกต่างระหว่าง:

window.onload = initAll();

และ

window.onload = initAll;

กรุณาอธิบายหลักการเบื้องหลัง


24
@JS Bangs - เป็นภาษาอังกฤษแบบสหรัฐอเมริกาเท่านั้น ไม่ใช่ที่อื่น แม้ว่าโปรแกรมเมอร์มักจะเรียกพวกเขาว่า "วงเล็บ" เพื่อหลีกเลี่ยงความสับสน แต่ในภาษาอังกฤษแบบสหราชอาณาจักรคนที่โค้งมนนั้นรู้จักกันในชื่อวงเล็บ รูปสี่เหลี่ยมจัตุรัสเรียกว่า "วงเล็บเหลี่ยม" en.wikipedia.org/wiki/Bracket
Rob Levine

13
ในบันทึกที่จริงจังชื่อ UNICODE อย่างเป็นทางการคือวงเล็บ 0028 ( LEFT PARENTHESIS = วงเล็บเปิด (1.0) และ 0029 ) RIGHT PARENTHESIS = วงเล็บปิด (1.0) - unicode.org/charts/charindex.html#P และสิ่งที่ Dictionary.com พูดเกี่ยวกับเรื่องนี้ - dictionary.reference.com/ เรียกดู / PARENTHESIS "เส้นโค้งตรงหรือทั้งสองแบบ, () ... "

8
นี่จึงไม่ใช่แค่ "ภาษาอังกฤษแบบสหรัฐอเมริกา" แต่เป็นคำจำกัดความมาตรฐานสากลเพราะ UNICODE เป็นมาตรฐานสากล

2
@fuzzy - คุณเอาข้อเท็จจริงมาจากไหนอย่างจริงจัง? {}เรียกว่ากระรอก
Anurag

7
@fuzzy lollipop - Unicode เป็นมาตรฐานสากลในการเข้ารหัสอักขระเป็นไบต์ไม่ใช่ในการตั้งชื่อ ผู้เขียนเอกสาร Unicode ไม่ได้อ้างว่าชื่อที่กำหนดสำหรับอักขระเป็นมาตรฐานสากล เป็นรหัสเทียบกับอักขระที่กำหนด แต่คุณอาจต้องการทราบว่าพวกเขายังอ้างถึง [และ] ว่าเป็นวงเล็บเหลี่ยม - (ไม่ใช่แค่ "วงเล็บ") และหมายถึง [, {และ (เป็นอักขระวงเล็บ) คุณควรพยายามทำความเข้าใจความแตกต่าง ในแบบที่สถานที่ต่างๆใช้คำเดียวกันสำคัญมากหากคุณเป็นส่วนหนึ่งของทีมต่างประเทศ
Rob Levine

คำตอบ:


160
window.onload = initAll();

นี้รัน initAll() ทันทีและกำหนดค่าตอบแทนฟังก์ชั่นของwindow.onloadการ โดยปกติจะไม่ใช่สิ่งที่คุณต้องการ initAll()จะต้องส่งคืนฟังก์ชันเพื่อให้เหมาะสม

window.onload = initAll;

สิ่งนี้กำหนดฟังก์ชันจริงให้window.onload- ซึ่งเป็นไปได้เพราะใน JavaScript ดังที่ @Felix กล่าวว่าฟังก์ชันเป็นอ็อบเจ็กต์ชั้นหนึ่ง - โดยไม่ต้องดำเนินการ initAllจะดำเนินการโดยเหตุการณ์โหลด


18
สิ่งสำคัญที่ต้องพูดถึงในที่นี้คือฟังก์ชันเป็นออบเจ็กต์ชั้นหนึ่งใน JavaScript
Felix Kling

135

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

ฉันจะไม่ใช้window.onloadเพราะมันถูกสร้างขึ้นมาเพื่อแสดงให้เห็น ฉันจะใช้ฟังก์ชันคูณอย่างง่ายเพื่อสาธิตแทน:

function Multiply(operator, operand) {
    return operator * operand;
}

สิ่งนี้สามารถเขียนได้อย่างเท่าเทียมกัน:

Multiply = function(operator, operand) {
    return operator * operand;
}

แม้ว่าในตัวอย่างแรกความหมายอาจไม่ชัดเจน แต่ตัวอย่างที่สองแสดงให้เห็นอย่างชัดเจนยิ่งขึ้นว่าเรากำลังกำหนดฟังก์ชันที่มีพารามิเตอร์ 2 ตัวให้กับตัวแปรที่เรียกว่าMultiplyและแนวคิดของฟังก์ชันนี้เป็นการกำหนดเป็นเรื่องธรรมดาใน JavaScript นี่เป็นการแสดงให้เห็นเล็กน้อยถึงความจริงที่ว่าฟังก์ชั่นเป็น"พลเมืองชั้นหนึ่ง"กล่าวคือสามารถส่งผ่านไปรอบ ๆ ได้ราวกับว่าเรากำลังส่งผ่านค่านิยม

ตอนนี้ถึงความแตกต่างของการมอบหมาย:

var operator = 3;
var operand = 4;
var ret = Multiply(operator, operand);

ณ จุดกำหนดตัวแปร ret Multiplyจะถูกเรียกใช้งานและกำหนดค่าส่งคืน - retจะเท่ากับ 12

ลองอีกครั้งด้วยวิธีอื่น:

var operator = 3;
var operand = 4;
var ret = Multiply;

ตอนนี้ที่จุดของการกำหนดret, retกลายเป็นของMultiplyฟังก์ชั่นเมื่อเทียบกับการเป็นผลที่ได้รับจากMultiplyการทำงาน การโทรไปที่ret()จะทำให้Multiplyฟังก์ชันของคุณถูกเรียกใช้งานและคุณสามารถเรียกมันได้เหมือนกับที่คุณเรียกMultiply(operator, operand):

var out = ret(3, 4);

เหมือนกับ

var out = Multiply(3, 4);

คุณได้อย่างมีประสิทธิภาพบอกว่าคุณจะใช้เป็นตัวแทนสำหรับret Multiply()เมื่อโทรretเราหมายถึงMultiplyฟังก์ชันจริงๆ

กลับไปที่window.onloadไฟล์. คิดว่าสิ่งนี้เป็น:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

initAll = function() {
    return 12;
}

อย่างที่คุณเห็นwindow.onloadมันเป็นฟังก์ชันเหมือนกับฟังก์ชันอื่น ๆ ไม่มีอะไรพิเศษเกี่ยวกับมัน คุณสามารถกำหนดค่ากำหนดฟังก์ชันเป็นโมฆะได้หากต้องการประเด็นก็คือไม่มีอะไรพิเศษไปwindow.onloadกว่าฟังก์ชันของคุณเอง สิ่งเดียวที่แตกต่างกันเล็กน้อยคือถูกเรียกโดยหน้าต่างเมื่อโหลด [คำเตือน: ฉันไม่เคยลบล้างฟังก์ชันของหน้าต่างเลยฉันไม่แน่ใจว่าสิ่งนี้จะทำให้เกิดผลกระทบเชิงลบหรือไม่ เราหวังว่าพวกเขาจะตรวจสอบดูว่ามีการกำหนดฟังก์ชันก่อนที่จะเรียกมันว่า ie if (window.onload) window.onload();]

ตอนนี้เรียกinitAll()สิ่งที่เรากำลังพูดคือ:

window.onload = initAll();

ซึ่งอาจกล่าวได้ว่า:

window.onload = 12;

แต่เมื่อเราพูดinitAllโดยไม่มีวงเล็บสิ่งที่เรากำลังพูดจริงๆคือ: ฉันต้องการแทนที่ฟังก์ชัน window.onload ของฉันด้วยฟังก์ชันใหม่นั่นคือฉันต้องการแทนที่ด้วยinitAllฟังก์ชันของฉันเพื่อให้การเรียกใช้window.onloadงานของฉันinitAllรหัส.

ดังนั้น:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

ถูกแทนที่ด้วย:

window.onload = function() {
    return 12;
}

ดังนั้นการเรียกใช้ใด ๆwindow.onloadจะเรียกใช้initAllฟังก์ชันของคุณแทนสิ่งที่window.onloadมีมา แต่เดิม คุณได้แทนที่ฟังก์ชันเดิมด้วยฟังก์ชันใหม่ของคุณ

ในความเป็นจริงคุณสามารถเขียนได้เท่า ๆ กัน:

window.onload = function() {
    //Write all your init code right in here instead of having a separate 
    //initAll function.
}

อีกตัวอย่างหนึ่งที่อาจแสดงให้เห็นได้ดีกว่าคือ:

var d = new Date();
var currentTime = d.getTime();

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

var currentTime = function() {
    var d = new Date();
    return d.getTime();
}

var a = currentTime(); //The current time at the point a is defined...
var b = currentTime;   //b is a functional reference to currentTime...
var c = b(); //The current time when variable c is defined
var d = c; //The current time when variable c was defined

สังเกตว่าเราโทรb()เข้าcและdมอบหมายงานตรงกับที่เราโทรได้currentTime()อย่างไร?


คำตอบที่ยอดเยี่ยม!
Shadi Almosri

เฮ้ฉันจะทำอย่างไรถ้าฉันต้องการเพิ่มฟังก์ชันที่รับอาร์กิวเมนต์ในตัวฟังเหตุการณ์

16

ฟังก์ชันในจาวาสคริปต์เป็นพลเมืองชั้นหนึ่งดังนั้นจึงสามารถกำหนดให้กับตัวแปรอื่น ๆ หรือส่งต่อเป็นอาร์กิวเมนต์ได้

ดังนั้นเมื่อคุณทำ

window.onload = initAll;

คุณกำลังตั้งค่าonloadคุณสมบัติของwindowวัตถุเพื่ออ้างอิงinitAllฟังก์ชันนั้นเอง

เมื่อคุณทำ

window.onload = initAll();

คุณกำลังตั้งค่าonloadคุณสมบัติเพื่อเก็บค่าส่งคืนของ initAll เนื่องจากจะดำเนินการในตำแหน่งบนบรรทัดนั้น


10

initAll เป็นการอ้างอิงถึงค่าฟังก์ชันและตัวดำเนินการวงเล็บต่อท้ายชื่อฟังก์ชันเรียกใช้อ็อบเจ็กต์ฟังก์ชันนี้

ดังนั้นหากคุณทำสิ่งที่ชอบ

a = initAll

จากนั้นaจะกลายเป็นเช่นเดียวกับinitAll- ตัวอย่างที่คุณทำได้a()- แต่ด้วย

a = initAll()

ตัวแปรaจะได้รับค่าตอบแทนของinitAllฟังก์ชันที่ดำเนินการ


8

ฉันมาช้าไป 6 ปี แต่ฉันรู้สึกว่าสิ่งนี้อธิบายได้ง่ายกว่าคำตอบข้างต้นมาก

นี่คือTLDR ; หรือมุมมองตานกเมื่อเรียกฟังก์ชั่นการใช้และการไม่ได้ใช้()'s

ให้ใช้ฟังก์ชันนี้เช่น:

function foo(){
return 123;
}

ถ้าคุณเข้าสู่ระบบ "foo" - โดยไม่ต้อง ()

console.log(foo); 

---outout------
function foo(){
return 123;
}

ที่ไม่ได้ใช้()วิธีการเรียกฟังก์ชั่นของตัวเอง คุณจะทำเช่นนี้ถ้าคุณต้องการให้ส่งต่อไปเป็นการโทรกลับ


ถ้าคุณเข้าสู่ระบบ "foo ()" - ด้วย ()

console.log(foo());
-----output-----
 123

ใช้()หลังจากที่ฟังก์ชั่นวิธีการที่จะดำเนินการฟังก์ชั่นและส่งกลับค่าของมัน

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