Come funziona questa funzione di restituzione di una funzione?

1

Sto avendo difficoltà a capire esattamente cosa sta succedendo nel codice qui e come questo script sta cambiando altre funzioni.

Questo è preso da eloquentjavascript.net capitolo 5 sulle funzioni di ordine superiore.

function noisy(f) {
  return function(arg) {
    console.log("calling with", arg);
    var val = f(arg);
    console.log("called with", arg, "- got", val);
    return val;
  };
}
noisy(Boolean)(0);

// → calling with 0
// → called with 0 - got false
    
posta user213229 28.01.2016 - 23:52
fonte

4 risposte

7

Poiché non è chiaro quale parte di questo ti confonda, facciamo questo passo dopo passo.

1) Boolean è una funzione. In questo caso, accetta un argomento e ritorna vero o falso a seconda che l'argomento sia vero o falso. Quindi, se aiuta, puoi sostituire Boolean con function(x) { return !!x; } e ottenere più o meno lo stesso comportamento.

2) Questa riga:

noisy(Boolean)(0);

è intercambiabile con:

var func = noisy(Boolean);
func(0);

Supponendo che l'identificatore func non sia utilizzato in nessun'altra parte del tuo codice.

3) noisy(Boolean) chiama ovviamente la funzione noisy , con f impostata sulla funzione Boolean . La chiamata a noisy restituisce quindi una funzione come questa:

function(arg) {
    console.log("calling with", arg);
    var val = Boolean(arg);
    console.log("called with", arg, "- got", val);
    return val;
}

4) La funzione restituita da noisy viene quindi chiamata con 0 come valore di arg . Ciò fa efficacemente quanto segue:

console.log("calling with", 0);
var val = Boolean(0);
console.log("called with", 0, "- got", val);
return val;

5) Se il n. 1 aveva senso, non dovrebbe sorprendere che Boolean(0) valuti a false . Da lì dovrebbe essere ovvio perché l'output è quello che è.

    
risposta data 29.01.2016 - 00:28
fonte
3

Considera la riga noisy(Boolean)(0);

Boolean è una funzione javascript che richiede un'opzione parametro.

La prima parte della riga in questione, noisy (Boolean) (0); , prende la funzione booleana e la passa nella funzione noisy come parametro.

La funzione noisy restituisce una (nuova) funzione che accetta un parametro ( return function(arg) ).

La seconda metà della riga in questione, rumorosa (booleana) (0) ; , prende il valore restituito di rumore (una funzione che accetta un parametro) e la invoca con il parametro 0 ;

La funzione restituita da noisy eseguirà un paio di scritture della console, ma nel frattempo invocherà la funzione originariamente inviata in noisy (la funzione Boolean , chiamata f ) con il parametro ( 0 , chiamato arg ), quindi cattura e passa il valore di ritorno di Boolean attraverso la variabile val .

Penso che sia fuorviante dire che questo sta cambiando qualsiasi funzione. Questo codice sta creando una nuova funzione che avvolge una funzione esistente con funzionalità extra.

In questo caso, questo codice avvolge semplicemente la funzione Boolean con un paio di chiamate a console.log, ma la funzione Boolean rimane invariata.

    
risposta data 29.01.2016 - 00:31
fonte
2

Prima di tutto ricorda che questo codice non sta cambiando / mutando la funzione passata. Passare al costruttore booleano è un po 'strano e può portare ad una certa confusione, quindi lasciala rimuoverla e scomporla di più per chiarezza.

var noisyIsArray = noisy(Array.isArray);

noisyIsArray([]);
> calling with []
> called with [] - got true
true

noisyIsArray(2);
> calling with 2
> called with 2 - got false
false

Nella sua forma più semplice, il rumore può assumere qualsiasi funzione e restituire una funzione. All'interno della funzione che restituisce, chiama la funzione che accetta. Prima di chiamarla, registra solo gli argomenti e restituisce il valore.

Nel caso precedente Array.isArray è la funzione che stiamo passando in noisy e var noisyIsArray è anche una funzione (la funzione restituita dal rumore).

Ecco una funzione di ordine superiore molto semplice (e non robusta):

function logSomething() {
    console.log('something');
}

function invoke(fn) {
    return function() {
        fn();
    }
}

var invokeLogSomething = invoke(logSomething);

invokeLogSomething();
>something

Tutto invoke fa è prendere una funzione e restituire una funzione che chiama la funzione passata. Non c'è nulla di speciale nel fatto che la chiamata alla funzione fn sia uguale a qualsiasi altra.

    
risposta data 29.01.2016 - 00:25
fonte
0

Questo JavaScript ha adattato e implementato due punti particolari:

  • a Chiusura : questa è un'abitabilità speciale di alcune lingue per catturare una variabile in un altro contesto.
  • il fatto che in Javascript qualsiasi variabile sia un oggetto (una stringa, un intero, una funzione, una classe, ...)

Questo frammento finalmente fornisce una funzione rumorosa () che può eseguire un'altra funzione con informazioni extra di debug.

Vediamo passo per passo:

function noisy(f)

Questa funzione accetta una funzione come argomento. Nessun problema: con JS una funzione è anche un oggetto.

return function(arg) {

La funzione noisy () restituisce un'altra funzione senza un nome (una funzione anonima ). Ancora nessun problema: con JS una funzione è anche un oggetto.

Si può notare che l'argomento f non è utilizzato ovunque nella funzione rumoroso () . Viene utilizzato solo nella funzione anonima. Se non conosci la Chiusura dovresti pensare che l'argomento f sia superfluo in rumoroso () e che dovrebbe generare un errore nella funzione anonima poiché non è dichiarato locale né globale. Infatti, grazie alla funzione Closure, l'argomento f viene effettivamente passato alla funzione anonima come variabile e questa variabile viene chiusa nel contesto della funzione. Questa è la variabile f non è più collegata all'argomento f dopo che la funzione anonima è stata effettivamente creata.

L'altra parte delle funzioni è piuttosto semplice: la funzione anonima esegue la funzione f e registra alcune informazioni di debug nella console, prima e dopo.

L'ultima parte del taglio è un test della funzione.

noisy(Boolean)(0);

Viene testato con la classe Booleano . Questa è una scelta strana per un test, ma funziona perché in JS una classe è un oggetto. Chiamare una classe come funzione crea semplicemente un nuovo oggetto di quel tipo. Un altro esempio ben noto è Date('2016-01-01') .

    
risposta data 29.01.2016 - 00:37
fonte

Leggi altre domande sui tag