Macht es in JavaScript einen Unterschied, ob ich eine Funktion mit Klammern aufrufe?

105

Beim Aufrufen einer Funktion mit leeren Klammern oder ohne Klammern ist mir ein Unterschied aufgefallen. Da ich jedoch keine Argumente an die Funktion übergebe, habe ich mich gefragt, was der Unterschied sein würde zwischen:

window.onload = initAll();

und

window.onload = initAll;

Bitte erläutern Sie das Prinzip dahinter.

Dean
quelle
24
@JS Bangs - Nur in US-Englisch; nicht anderswo. Obwohl Programmierer dazu neigen, sie "Klammern" zu nennen, um Verwirrung zu vermeiden, werden die abgerundeten im britischen Englisch einfach als Klammern bezeichnet. Die quadratischen werden als "eckige Klammern" bezeichnet. en.wikipedia.org/wiki/Bracket
Rob Levine
13
Im Ernst, der offizielle UNICODE-Name ist Parenthesis. 0028 ( LINKE PARENTHESE = Klammer öffnen (1.0) und 0029 ) RECHTE PARENTHESE = Klammer schließen (1.0) - unicode.org/charts/charindex.html#P und was Dictionary.com dazu zu sagen hat - dictionary.reference.com/ browse / PARENTHESIS "Eine oder beide der aufrecht gekrümmten Linien, () ..."
8
Dies ist also nicht nur eine "US-Englisch" -Sache, sondern eine internationale Standarddefinition, da UNICODE ein internationaler Standard ist.
2
@fuzzy - Woher nimmst du deine Fakten ernsthaft? {}werden Eichhörnchenklammern genannt.
Anurag
7
@fuzzy lollipop - Unicode ist ein internationaler Standard zum Codieren von Zeichen als Bytes, nicht zum Benennen. Die Autoren des Unicode-Dokuments behaupten nicht, dass der Vorname für ein Zeichen ein internationaler Standard ist. Es ist der Code gegen das Zeichen, das sie definieren. Sie möchten jedoch vielleicht darauf hinweisen, dass sie sich auch auf [und] als eckige Klammern beziehen - (nicht nur auf "Klammern") und dass sie sich auf alle [, {und (als Klammerzeichen beziehen. Sie sollten sich bemühen, die Nuancen zu verstehen In der Art und Weise verwenden verschiedene Orte die gleichen Wörter. Sehr wichtig, wenn Sie Teil eines internationalen Teams sind.
Rob Levine

Antworten:

161
window.onload = initAll();

Dies wird initAll() sofort ausgeführt und weist den Rückgabewert der Funktion zu window.onload. Dies ist normalerweise nicht das, was Sie wollen. initAll()müsste eine Funktion zurückgeben, damit dies Sinn macht.

window.onload = initAll;

Dies weist die eigentliche Funktion zu window.onload- dies ist möglich, weil in JavaScript, wie @Felix sagt, Funktionen erstklassige Objekte sind - ohne sie auszuführen. initAllwird vom Ladeereignis ausgeführt.

Pekka
quelle
18
Es ist wichtig zu erwähnen, dass Funktionen erstklassige Objekte in JavaScript sind.
Felix Kling
136

Was Pekka sagt, ist richtig, aber ich möchte ein wenig mit einem Beispiel näher darauf eingehen, das jemandem helfen wird, der Funktionszeiger oder Delegierte nicht vollständig versteht.

Ich werde nicht verwenden, window.onloadweil das ein bisschen erfunden ist, um zu demonstrieren. Ich werde stattdessen eine einfache Multiplikationsfunktion verwenden, um zu demonstrieren:

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

Dies könnte ebenso geschrieben werden:

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

Während im ersten Beispiel die Implikation möglicherweise nicht offensichtlich ist, zeigt das zweite Beispiel deutlicher, dass wir einer Variablen namens eine Funktion mit zwei Parametern zuweisen Multiply, und dieses Konzept von Funktionen als Zuweisungen ist in JavaScript üblich. Dies ist eine kleine Demonstration der Tatsache, dass Funktionen "Bürger erster Klasse" sind , das heißt, sie können genau so weitergegeben werden, als würden wir Werte weitergeben.

Nun also zum Unterschied der Zuordnung:

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

Zum Zeitpunkt der Definition der Ret-Variablen Multiplywird ausgeführt und der Rückgabewert zugewiesen - retwird gleich 12.

Versuchen wir das noch einmal anders:

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

Nun, an der Stelle definiert ret, retwird Ihre MultiplyFunktion im Gegensatz zu dem aus dem erhaltenen Ergebnis, MultiplyFunktion. Durch Aufrufe von ret()wird Ihre MultiplyFunktion ausgeführt, und Sie können sie genau so aufrufen, als hätten Sie Folgendes aufgerufen Multiply(operator, operand):

var out = ret(3, 4);

ist das gleiche wie

var out = Multiply(3, 4);

Sie haben effektiv gesagt, dass Sie retals Delegierter für verwenden werden Multiply(). Beim Aufruf retbeziehen wir uns wirklich auf die MultiplyFunktion.

Zurück zu deinem window.onload. Stellen Sie sich das vor als:

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

initAll = function() {
    return 12;
}

Wie Sie sehen können, window.onloadist eine Funktion wie jede andere Funktion nichts Besonderes. Sie können ihm einen Wert zuweisen, ihm eine Funktion zuweisen, ihn auf Wunsch auf Null setzen - der Punkt ist, dass es nichts Besonderes window.onloadgibt als Ihre eigene Funktion. Das einzig etwas andere ist, dass es beim Laden vom Fenster aufgerufen wird. [Haftungsausschluss: Ich habe Fensterfunktionen nie auf Null gesetzt, daher bin ich mir nicht sicher, ob dies negative Auswirkungen haben wird. Man würde hoffen, dass sie prüfen, ob eine Funktion zugewiesen ist, bevor sie aufgerufen werden, dh if (window.onload) window.onload();].

Jetzt nennen initAll()wir: Wir sagen:

window.onload = initAll();

was genauso gut sagen könnte:

window.onload = 12;

Aber wenn wir sagen , initAllohne Klammern, sind , was wir wirklich sagen will , ist: Ich möchte zu ersetzen , was meine window.onload Funktion ist, mit einer neuen Funktion - also ich es mit meinem ersetzen wollen initAllFunktion, so dass alle Anrufe window.onloadläuft mein initAllCode.

So:

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

wird ersetzt durch:

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

Jeder Aufruf von window.onloadführt also Ihre initAllFunktion aus, anstatt was window.onloadursprünglich war. Sie haben die ursprüngliche Funktion durch Ihre neue Funktion ersetzt.

In der Tat könnten Sie gleichermaßen schreiben:

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

Ein weiteres Beispiel, das möglicherweise besser demonstriert, ist Folgendes:

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

Was auch immer die Zeit zu der Zeit war, die ddefiniert ist, wird zugewiesen currentTime. Großartig, aber das ist nur nützlich, wenn wir herausfinden möchten, wann die Funktion, die diesen Code enthält, aufgerufen wurde - dh zum Zeitpunkt des Ladens der Seite. Was ist, wenn wir die aktuelle Zeit jederzeit anzeigen möchten 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

Beachten Sie, wie wir b()unsere cund dAufgaben genau so anrufen, wie wir anrufen könnten currentTime()?

BenAlabaster
quelle
Wunderbare Antwort!
Shadi Almosri
Hey, was ist, wenn ich eine Funktion hinzufügen möchte, die Argumente für einen Ereignis-Listener akzeptiert?
Shemiroth
16

Funktionen in Javascript sind erstklassige Bürger und können als solche anderen Variablen zugewiesen oder als Argumente weitergegeben werden.

Also, wenn du es tust

window.onload = initAll;

Sie legen die onloadEigenschaft des windowObjekts fest, um auf die initAllFunktion selbst zu verweisen .

Wenn Sie das tun

window.onload = initAll();

Sie legen die onloadEigenschaft so fest, dass sie den Rückgabewert von initAll enthält, da sie in dieser Zeile ausgeführt wird.

Peter Bailey
quelle
10

initAll ist eine Referenz auf einen Funktionswert, und der an den Funktionsnamen angehängte Operator in Klammern führt dieses Funktionsobjekt aus.

Also, wenn Sie so etwas tun

a = initAll

dann awird das gleiche wie initAll- zum Beispiel können Sie a()- aber mit

a = initAll()

Die Variable aerhält den Rückgabewert der ausgeführten initAllFunktion

Andris
quelle
8

Ich bin 6 Jahre zu spät, aber ich denke, das hätte viel einfacher erklärt werden können als die obigen Antworten.

Also hier ist der TLDR ; oder Vogelperspektive beim Aufrufen von Funktionen mit und ohne Verwendung von ()'s

Nehmen wir zum Beispiel diese Funktion:

function foo(){
return 123;
}

wenn du "foo" loggst - ohne ()

console.log(foo); 

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

Verwenden Sie keine ()Mittel, um die Funktion selbst abzurufen . Sie würden dies tun, wenn Sie möchten, dass es als Rückruf weitergegeben wird.


wenn Sie "foo ()" anmelden - mit ()

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

Unter Verwendung ()nach Funktionsmittel , die Funktion auszuführen und seinen Wert zurückgeben .

Garrettmac
quelle