Funktionen, die eine Funktion zurückgeben

109

Ich bleibe bei diesem Konzept von 'Funktionen, die Funktionen zurückgeben'. Ich beziehe mich auf das Buch 'Object Oriented Javascript' von Stoyan Stefanov.

Snippet One:

    function a() {
      
        alert('A!');
    
        function b(){
            alert('B!'); 
        }
    
        return b();
    }
    
    var s = a();
    alert('break');
    s();

Ausgabe:

A!
B!
break

Snippet Zwei

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b;
}

var s = a();
alert('break');
s();
Ausgabe:

A!
break
B!

Kann mir bitte jemand den Unterschied zwischen der Rückkehr bund b()den obigen Ausschnitten erklären?

Cafecorridor
quelle
2
Sie werden feststellen, dass das erste Snippet einen Fehler bei s () ausgibt.
Weirdalsuperfan

Antworten:

121

Durch Zuweisen einer Variablen zu einer Funktion (ohne Klammer) wird der Verweis auf die Funktion kopiert. Wenn Sie die Klammer an das Ende eines Funktionsnamens setzen, wird die Funktion aufgerufen und der Rückgabewert der Funktionen zurückgegeben.

Demo

function a() {
    alert('A');
}
//alerts 'A', returns undefined

function b() {
    alert('B');
    return a;
}
//alerts 'B', returns function a

function c() {
    alert('C');
    return a();
}
//alerts 'C', alerts 'A', returns undefined

alert("Function 'a' returns " + a());
alert("Function 'b' returns " + b());
alert("Function 'c' returns " + c());

In Ihrem Beispiel definieren Sie auch Funktionen innerhalb einer Funktion. Sowie:

function d() {
    function e() {
        alert('E');
    }
    return e;
}
d()();
//alerts 'E'

Die Funktion ist weiterhin aufrufbar. Es existiert noch. Dies wird ständig in JavaScript verwendet. Funktionen können herumgereicht werden , nur wie andere Werte. Folgendes berücksichtigen:

function counter() {
    var count = 0;
    return function() {
        alert(count++);
    }
}
var count = counter();
count();
count();
count();

Die Funktionsanzahl kann die Variablen, die außerhalb definiert wurden, beibehalten. Dies wird als Schließung bezeichnet. Es wird auch häufig in JavaScript verwendet.

kzh
quelle
Snippet Eins: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: hero.sayName} hero.nayName (); Snippet 2: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: this.sayName} hero.nayName (); Das erste Snippet gibt mir die richtige Ausgabe, das zweite nicht. Warum? Grüße.
Cafecorridor
thisbedeutet nur etwas innerhalb eines Funktionskörpers, sonst ist es global. Was Sie sagen, this.sayNameist, dass Sie die globale Variable wollen, sayNamedie nicht existiert, sie ist undefiniert und daher nicht aufrufbar.
kzh
7
Ich war verwirrt von d () (); zuerst aber dann erkannt, dass die erste () d und die zweite () den Rückgabewert von d aufruft, der e ist.
Skud
1
Acht Jahre später und das ist immer noch relevant!
Brad Vanderbush
45

Wenn Sie den Funktionsnamen ohne ()zurückgeben, wird ein Verweis auf die Funktion zurückgegeben, der wie gewünscht zugewiesen werden kann var s = a(). sEnthält jetzt einen Verweis auf die Funktion b(), und das Aufrufen s()entspricht funktional dem Aufrufen b().

// Return a reference to the function b().
// In your example, the reference is assigned to var s
return b;

Wenn Sie die Funktion mit ()in einer return-Anweisung aufrufen, wird die Funktion ausgeführt und der von der Funktion zurückgegebene Wert zurückgegeben. Es ähnelt dem Aufrufen var x = b();, aber anstatt den Rückgabewert von b()Ihnen zuzuweisen, geben Sie ihn von der aufrufenden Funktion zurück a(). Wenn die Funktion b()selbst keinen Wert zurückgibt, wird der Aufruf undefinednach allen anderen Arbeiten zurückgegeben b().

// Execute function b() and return its value
return b();
// If b() has no return value, this is equivalent to calling b(), followed by
// return undefined;
Michael Berkowski
quelle
1
Von allen Antworten hat mir Ihre Antwort aufgrund ihrer Einfachheit besser gefallen.
Anar Khalilov
Gut ausgedrückt! Sehr leicht zu verstehen, diese Antwort.
AndrewSteinheiser
Vielen Dank für die Überprüfung des Bits, wenn die Funktion keinen Wert zurückgibt, gibt der Aufruf undefiniert zurück. Ich habe dieses Durcheinander kürzlich entdeckt: Selbst wenn die Funktion explizit null zurückgibt, ist der Wert, der einer Variablen zurückgegeben wird, undefiniert und nicht null. Ich stelle mir vor, dass dies in einigen Codebasen viele seltsame Probleme verursacht hat, da null und undefiniert nicht absolut gleichwertig mit === sind.
Benjamin
37

return b(); ruft die Funktion b () auf und gibt das Ergebnis zurück.

return b; Gibt einen Verweis auf die Funktion b zurück, die Sie in einer Variablen speichern können, um sie später aufzurufen.

Abdo
quelle
17

Beim Zurückgeben bwird ein Funktionsobjekt zurückgegeben. In Javascript sind Funktionen wie jedes andere Objekt nur Objekte. Wenn Sie das nicht hilfreich finden, ersetzen Sie einfach das Wort "Objekt" durch "Ding". Sie können jedes Objekt von einer Funktion zurückgeben. Sie können einen True / False-Wert zurückgeben. Eine ganze Zahl (1,2,3,4 ...). Sie können eine Zeichenfolge zurückgeben. Sie können ein komplexes Objekt mit mehreren Eigenschaften zurückgeben. Und Sie können eine Funktion zurückgeben. Eine Funktion ist nur eine Sache.

In Ihrem Fall bgibt die Rückgabe das Ding zurück, das Ding ist eine aufrufbare Funktion. Rückgabe b()gibt den von der aufrufbaren Funktion zurückgegebenen Wert zurück.

Betrachten Sie diesen Code:

function b() {
   return 42;
}

Unter Verwendung der obigen Definition wird return b();der Wert 42 zurückgegeben. Andererseits wird return b;eine Funktion zurückgegeben, die selbst den Wert 42 zurückgibt. Dies sind zwei verschiedene Dinge.

Cheeso
quelle
4
es sollte zurückkehren 42;)
c69
4

Wenn Sie zurückkehren b, ist dies nur ein Verweis auf Funktion b, wird jedoch zu diesem Zeitpunkt nicht ausgeführt.

Wenn Sie zurückkehren b(), führen Sie die Funktion aus und geben ihren Wert zurück.

Versuchen alertSie es typeof(s)in Ihren Beispielen. Snippet b gibt Ihnen 'Funktion'. Was wird dir ein Schnipsel geben?

vzwick
quelle
Zuerst gibt man 'undefiniert'. Bedeutet das, dass return b () völlig nutzlos ist? Auch im zweiten Snippet ist Funktion b privat. Wie können wir dann auf die Referenz außerhalb der Funktion zugreifen? Bitte geben Sie mir einen Link, der dieses Konzept möglichst klar erklärt. Vielen Dank!
Cafecorridor
Ich habe die Antwort auf die erste bekommen. Geben Sie 1 + 2 in Funktion b () zurück und der Typ zeigt die Zahl an. Vielen Dank.
Cafecorridor
Ich bin froh, dass du es herausgefunden hast! Was die private Funktion betrifft: Sie ist im zweiten Beispiel nicht wirklich privat, da Sie sie bereits zurückgegeben haben. In der Tat wird es zugewiesen s. Versuchen Sie es return thisstatt return b... Sie werden es s.b()dann tun können ;)
vzwick
Ich werde es auf jeden Fall ausprobieren. Ich habe dieses Konzept in Javascript noch nicht erreicht. Vielleicht in ein paar Tagen. Vielen Dank! :)
Cafecorridor
Funktion a () {alert ("A!"); Funktion b () {alert ("B!"); } return b; } var s = a (); lösche a; s (); ---- end ---- Ist das Referenzkonzept in Javascript dasselbe wie in Java? Hier habe ich die Funktion a () gelöscht und dennoch führt ein Aufruf von s () b () aus. Kann ich also sagen, dass s eine Kopie von b enthält und nicht auf b () zeigt, das in a () definiert ist?
Cafecorridor
2

Stellen Sie sich die Funktion als Typ vor, wie einen Int. Sie können Ints in einer Funktion zurückgeben. Sie können auch Funktionen zurückgeben, sie sind Objekte vom Typ "Funktion".

Nun das Syntaxproblem: Da Funktionen Werte zurückgeben, wie können Sie eine Funktion zurückgeben und nicht einen Wert?

durch Weglassen von Klammern! Denn ohne Klammern wird die Funktion nicht ausgeführt! So:

return b;

Gibt die "Funktion" zurück (stellen Sie sich vor, Sie geben eine Zahl zurück), während:

return b();

Führt zuerst die Funktion aus und gibt dann den Wert zurück, der durch Ausführen erhalten wurde. Das ist ein großer Unterschied!

Francesco Belladonna
quelle
Im zweiten Snippet ist die Funktion b privat. Wie können wir dann außerhalb der Funktion auf die Referenz zugreifen? Gibt es Regeln, die dasselbe regeln?
Cafecorridor
Objekte in JavaScript (einschließlich Funktionen) sind nicht mehr privat, wenn Sie sie freigeben.
kzh
@Cafecorridor: Wenn die private Funktion von etwas zurückgegeben wird (eine öffentliche Funktion) oder einer öffentlichen Variablen zugewiesen ist (also einer auf Anwendungen zugänglichen Variablen), können Sie Ihre Variable einfach ausführen (); , andernfalls weisen Sie die zurückgegebene Funktion einer Variablen zu und wiederholen Sie Ihre
Francesco Belladonna
2

Erstellen Sie eine Variable :

var thing1 = undefined;

Deklarieren Sie eine Funktion :

function something1 () {
    return "Hi there, I'm number 1!";
}

Benachrichtigen Sie den Wert von thing1(unserer ersten Variablen):

alert(thing1); // Outputs: "undefined".

Wenn wir thing1nun ein Verweis auf die Funktion sein wollten something1, was bedeutet, dass es dasselbe ist wie unsere erstellte Funktion, würden wir Folgendes tun:

thing1 = something1;

Wenn wir jedoch den return Wert der Funktion wollen, müssen wir ihm den Rückgabewert der ausgeführten Funktion zuweisen. Sie führen die Funktion in Klammern aus:

thing1 = something1(); // Value of thing1: "Hi there, I'm number 1!" 
Shaz
quelle
-1

Ausschnitt eins:

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b(); //return nothing here as b not defined a return value
}

var s = a(); //s got nothing assigned as b() and thus a() return nothing.
alert('break');
s(); // s equals nothing so nothing will be executed, JavaScript interpreter will complain

Die Anweisung 'b ()' bedeutet, die Funktion 'b' auszuführen, die ein Dialogfeld mit dem Text 'B!' zeigt.

die Aussage 'return b ();' bedeutet, eine Funktion mit dem Namen 'b' auszuführen und dann zurückzugeben, welche Funktion 'b' zurückgibt. aber 'b' gibt nichts zurück, dann gibt diese Anweisung 'return b ()' auch nichts zurück. Wenn b () eine Zahl zurückgibt, ist 'return b ()' auch eine Zahl.

Jetzt wird 's' der Wert von 'a ()' zurückgegeben, was 'b ()' zurückgibt, was nichts ist, also ist 's' nichts (in JavaScript ist es tatsächlich eine Sache, es ist eine 'undefinierte'. Also Wenn Sie JavaScript bitten, den Datentyp 's' zu interpretieren, teilt Ihnen der JavaScript-Interpreter mit, dass 's' undefiniert ist.) Da 's' undefiniert ist, wenn Sie JavaScript bitten, diese Anweisung 's ()' auszuführen, Sie fordern JavaScript auf, eine Funktion mit dem Namen 's' auszuführen, aber 's' ist hier eine 'undefinierte', keine Funktion, daher beschwert sich JavaScript: "Hey, s ist keine Funktion, ich weiß nicht wie Um dies zu tun s ", wird eine Fehlermeldung" Uncaught TypeError: s ist keine Funktion "von JavaScript angezeigt (getestet in Firefox und Chrome).


Snippet Zwei

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b; //return pointer to function b here
}

var s = a();  //s get the value of pointer to b
alert('break');
s(); // b() function is executed

Jetzt gibt die Funktion 'a' einen Zeiger / Alias ​​auf eine Funktion mit dem Namen 'b' zurück. Wenn also 's = a ()' ausgeführt wird, erhält 's' einen Wert, der auf b zeigt, dh 's' ist jetzt ein Alias ​​von 'b'. Der Aufruf von 's' entspricht dem Aufruf von 'b'. dh 's' ist jetzt eine Funktion. Execute 's ()' bedeutet, dass die Funktion 'b' ausgeführt wird (wie beim Ausführen von 'b ()'), einem Dialogfeld mit 'B!' wird angezeigt (dh Ausführen der 'alert (' B! '); Anweisung in der Funktion' b ')

Henry Pilot bei der Arbeit
quelle
-2

Dies ist im wirklichen Leben sehr nützlich.

Arbeiten mit Express.js

Ihre reguläre expressRoute sieht also so aus:

function itWorksHandler( req, res, next ) {
  res.send("It works!");
}

router.get("/check/works", itWorksHandler );

Aber was ist, wenn Sie einen Wrapper, einen Fehlerhandler oder etwas hinzufügen müssen?

Dann rufen Sie Ihre Funktion über einen Wrapper auf.

function loggingWrapper( req, res, next, yourFunction ) {
  try {
    yourFunction( req, res );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", function( req, res, next ) {
  loggingWrapper( req, res, next, itWorksHandler );
});

Sieht kompliziert aus? Wie wäre es damit:

function function loggingWrapper( yourFunction ) => ( req, res, next ) {
  try {
    yourFunction( req, res, next );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", loggingWrapper( itWorksHandler ) );

Sehen Sie am Ende, dass Sie eine Funktion loggingWrappermit einem Argument als eine andere Funktion übergeben itWorksHandlerund loggingWrappereine neue Funktion zurückgeben, die req, res, nextals Argumente verwendet wird.

Zilvinas
quelle