Funzioni che restituiscono una funzione


110

Sono bloccato con questo concetto di "Funzioni che restituiscono funzioni". Mi riferisco al libro "Object Oriented Javascript" di Stoyan Stefanov.

Snippet One:

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

Produzione:

A!
B!
break

Snippet Two

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

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

    return b;
}

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

A!
break
B!

Qualcuno può dirmi la differenza tra il ritorno be b()negli snippet sopra?


2
Noterai che il primo frammento restituisce un errore su s ();
weirdalsuperfan

Risposte:


122

Assegnare una variabile a una funzione (senza parentesi) copia il riferimento alla funzione. Mettendo la parentesi alla fine del nome di una funzione, chiama la funzione, restituendo il valore di ritorno della funzione.

dimostrazione

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());

Nel tuo esempio, stai anche definendo funzioni all'interno di una funzione. Ad esempio:

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

La funzione è ancora richiamabile. Esiste ancora. Viene utilizzato in JavaScript tutto il tempo. Le funzioni possono essere trasmesse proprio come gli altri valori. Considera quanto segue:

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

La funzione count può mantenere le variabili che sono state definite al di fuori di essa. Questa è chiamata chiusura. È anche molto utilizzato in JavaScript.


Snippet One: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: hero.sayName} hero.nayName (); Snippet due: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: this.sayName} hero.nayName (); Il primo frammento mi dà l'output corretto mentre il secondo no. Perché? Saluti.
Cafecorridor

thissignifica solo qualcosa all'interno di un corpo di funzione, altrimenti è globale. Quello che stai dicendo this.sayNameè che vuoi la variabile globale sayNameche non esiste, non è definita, quindi non è richiamabile.
kzh

7
Sono stato confuso dal d () (); all'inizio ma poi si è reso conto che la prima () chiama de la seconda () chiama il valore di ritorno di d, che è e.
skud

1
Otto anni dopo e questo è ancora rilevante!
Brad Vanderbush

45

La restituzione del nome della funzione senza ()restituisce un riferimento alla funzione, che può essere assegnata come hai fatto con var s = a(). sora contiene un riferimento alla funzione b()e la chiamata s()è funzionalmente equivalente alla chiamata b().

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

La chiamata della funzione con ()in un'istruzione return esegue la funzione e restituisce il valore restituito dalla funzione. È simile alla chiamata var x = b();, ma invece di assegnare il valore di b()ritorno lo stai restituendo dalla funzione chiamante a(). Se la funzione b()stessa non restituisce un valore, la chiamata ritorna undefineddopo qualsiasi altra operazione eseguita da 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;

1
Di tutte le risposte, mi è piaciuta di più la tua risposta per la sua semplicità.
anar khalilov

Ben messo! Molto facile da capire questa risposta.
AndrewSteinheiser

Grazie per aver convalidato il bit sul fatto che la funzione non restituisca un valore che la chiamata restituisce non definito. Ho scoperto di recente questo pasticcio: anche se la funzione restituisce esplicitamente null, se si assegna il valore restituito a una variabile sarà indefinito, non null. Immagino che questo abbia causato molti strani problemi in alcune basi di codice, perché null e undefined non sono assolutamente equivalenti a ===.
Benjamin

37

return b(); chiama la funzione b () e ne restituisce il risultato.

return b; restituisce un riferimento alla funzione b, che è possibile memorizzare in una variabile da chiamare in seguito.


17

Il ritorno bsta restituendo un oggetto funzione. In Javascript, le funzioni sono solo oggetti, come qualsiasi altro oggetto. Se trovi che non è utile, sostituisci semplicemente la parola "oggetto" con "cosa". Puoi restituire qualsiasi oggetto da una funzione. Puoi restituire un valore vero / falso. Un numero intero (1,2,3,4 ...). Puoi restituire una stringa. Puoi restituire un oggetto complesso con più proprietà. E puoi restituire una funzione. una funzione è solo una cosa.

Nel tuo caso, la restituzione brestituisce la cosa, la cosa è una funzione richiamabile. La restituzione b()restituisce il valore restituito dalla funzione richiamabile.

Considera questo codice:

function b() {
   return 42;
}

Utilizzando la definizione di cui sopra, return b();restituisce il valore 42. D'altra parte return b;restituisce una funzione, che a sua volta restituisce il valore di 42. Sono due cose diverse.


4
dovrebbe tornare 42;)
c69

4

Quando torni b, è solo un riferimento alla funzione b, ma non in esecuzione in questo momento.

Quando torni b(), stai eseguendo la funzione e restituendo il suo valore.

Prova alerting typeof(s)nei tuoi esempi. Lo snippet b ti darà la "funzione". Cosa ti darà uno snippet?


Il primo dà "undefined". Significa che il ritorno b () è completamente inutile? Inoltre, nel secondo frammento, la funzione b è privata. Come possiamo quindi accedere al riferimento al di fuori della funzione? Forniscimi un collegamento che spieghi chiaramente questo concetto, se possibile. Grazie!
Cafecorridor

Ho la risposta al primo. restituisce 1 + 2 nella funzione b () e il tipo di mostra il numero. Grazie.
Cafecorridor

Sono contento che tu l'abbia capito! Per quanto riguarda la funzione privata: non è realmente privata nel secondo esempio poiché l'hai già restituita. In effetti, viene assegnato a s. Prova return thisinvece di return bperò ... Sarai in grado di farlo s.b()allora;)
vzwick

Lo proverò di sicuro. Non ho ancora raggiunto questo concetto in Javascript. Forse tra un paio di giorni. Grazie! :)
Cafecorridor

funzione a () {alert ("A!"); funzione b () {alert ("B!"); } return b; } var s = a (); eliminare un; S(); ---- fine ---- Il concetto di riferimento in Javascript è lo stesso di Java? Qui ho cancellato la funzione a () e tuttavia una chiamata a s () esegue b (). Quindi posso dire che s contiene una copia di be non punta a b () definito in a ()?
Cafecorridor

2

Immagina la funzione come un tipo, come un int. Puoi restituire int in una funzione. Puoi anche restituire funzioni, sono oggetti di tipo "funzione".

Ora il problema di sintassi: poiché le funzioni restituiscono valori, come puoi restituire una funzione e non restituisce un valore?

omettendo le parentesi! Perché senza parentesi, la funzione non verrà eseguita! Così:

return b;

Restituirà la "funzione" (immagina di restituire un numero), mentre:

return b();

Prima esegue la funzione poi restituisce il valore ottenuto eseguendola, è una grande differenza!


Nel secondo frammento, la funzione b è privata. Come possiamo quindi accedere al riferimento al di fuori della funzione? Esistono regole che disciplinano lo stesso?
Cafecorridor

Gli oggetti in JavaScript (comprese le funzioni) non sono più privati ​​se vengono condivisi.
kzh

@Cafecorridor: se la funzione privata viene restituita da qualcosa (una funzione pubblica) o è assegnata a una variabile pubblica (beh, una variabile accessibile dall'applicazione), puoi facilmente fare yourvariable (); , altrimenti assegna la funzione restituita a una variabile e ripeti yourvariable ();
Francesco Belladonna

2

Crea una variabile :

var thing1 = undefined;

Dichiarare una funzione :

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

Avvisa il valore di thing1(la nostra prima variabile):

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

Ora, se volessimo thing1essere un riferimento alla funzione something1, nel senso che sarebbe la stessa cosa della nostra funzione creata, dovremmo fare:

thing1 = something1;

Tuttavia, se vogliamo il return valore della funzione, dobbiamo assegnargli il valore di ritorno della funzione eseguita. Esegui la funzione usando le parentesi:

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

-1

Snippet uno:

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

l'istruzione "b ()" significa eseguire la funzione denominata "b" che mostra una finestra di dialogo con il testo "B!"

l'istruzione "return b ();" significa eseguire una funzione denominata "b" e quindi restituire la funzione "b" restituita. ma "b" non restituisce nulla, quindi anche questa istruzione "return b ()" non restituisce nulla. Se b () restituisce un numero, anche 'return b ()' è un numero.

Ora a 's' viene assegnato il valore di what 'a ()' return, che restituisce 'b ()', che non è niente, quindi 's' non è niente (in JavaScript è una cosa in realtà, è un 'indefinito'. quando chiedi a JavaScript di interpretare quale tipo di dati sia la 's', l'interprete JavaScript ti dirà che 's' è un non definito.) Poiché 's' è un non definito, quando chiedi a JavaScript di eseguire questa istruzione 's ()', stai chiedendo a JavaScript di eseguire una funzione denominata 's', ma 's' quièun 'indefinito', non una funzione, quindi JavaScript si lamenterà, "hey, s non è una funzione, non so come a che fare con questo ", quindi un messaggio di errore" Errore di tipo non rilevato: s non è una funzione "verrà mostrato da JavaScript (testato in Firefox e Chrome)


Snippet Two

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

ora, la funzione "a" restituisce un puntatore / alias a una funzione denominata "b". quindi quando si esegue 's = a ()', 's' otterrà un valore che punta a b, cioè 's' è un alias di 'b' ora, chiamare 's' equivale a chiamare 'b'. ie 's' è una funzione ora. Eseguire "s ()" significa eseguire la funzione "b" (come eseguire "b ()"), una finestra di dialogo che mostra "B!" apparirà (cioè eseguendo l'istruzione 'alert (' B! '); nella funzione' b ')


-2

Questo è molto utile nella vita reale.

Lavorare con Express.js

Quindi il tuo expresspercorso normale ha questo aspetto:

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

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

Ma cosa succede se è necessario aggiungere un wrapper, un gestore di errori o uno smth?

Quindi invoca la tua funzione da un wrapper.

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 );
});

Sembra complicato? Bene, che ne dici di questo:

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 ) );

Vedi alla fine stai passando una funzione loggingWrappercon un argomento come un'altra funzione itWorksHandler, e il tuo loggingWrapperrestituisce una nuova funzione che prende req, res, nextcome argomenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.