Fonctions qui renvoient une fonction


110

Je suis coincé avec ce concept de «fonctions qui renvoient des fonctions». Je fais référence au livre «Object Oriented Javascript» de Stoyan Stefanov.

Extrait un:

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

Production:

A!
B!
break

Extrait deux

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

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

    return b;
}

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

A!
break
B!

Quelqu'un peut-il me dire la différence entre le retour bet b()les extraits ci-dessus?


2
Vous remarquerez que le premier extrait donne une erreur sur s ();
weirdalsuperfan

Réponses:


122

L'affectation d'une variable à une fonction (sans les parenthèses) copie la référence à la fonction. Mettre la parenthèse à la fin d'un nom de fonction, appelle la fonction, renvoyant la valeur de retour des fonctions.

Démo

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

Dans votre exemple, vous définissez également des fonctions dans une fonction. Tel que:

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

La fonction est toujours appelable. Il existe toujours. Ceci est utilisé en JavaScript tout le temps. Les fonctions peuvent être passés autour de tout comme d' autres valeurs. Considérer ce qui suit:

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

Le nombre de fonctions peut conserver les variables définies en dehors de celui-ci. C'est ce qu'on appelle une fermeture. Il est également beaucoup utilisé en JavaScript.


Extrait de code un: var hero = {nom: 'Rafaelo', sayName: function () {return hero.name; }, nayName: hero.sayName} hero.nayName (); Extrait deux: var hero = {nom: 'Rafaelo', sayName: function () {return hero.name; }, nayName: this.sayName} hero.nayName (); Le premier extrait me donne la sortie correcte tandis que le second ne le fait pas. Pourquoi? Cordialement.
Cafecorridor

thissignifie seulement quelque chose à l'intérieur d'un corps de fonction, sinon il est global. Ce que vous dites, this.sayNamec'est que vous voulez la variable globale sayNamequi n'existe pas, elle n'est pas définie, elle n'est donc pas appelable.
kzh

7
J'étais confus par le d () (); au début, mais ensuite réalisé que le premier () appelle d et le second () appelle la valeur de retour de d, qui est e.
skud

1
Huit ans plus tard et c'est toujours d'actualité!
Brad Vanderbush

45

Renvoyer le nom de la fonction sans ()renvoie une référence à la fonction, qui peut être affectée comme vous l'avez fait var s = a(). scontient maintenant une référence à la fonction b(), et appeler s()est fonctionnellement équivalent à appeler b().

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

L'appel de la fonction avec ()dans une instruction return exécute la fonction et renvoie la valeur renvoyée par la fonction. C'est similaire à l'appel var x = b();, mais au lieu d'attribuer la valeur de retour de b()vous, vous la renvoyez depuis la fonction appelante a(). Si la fonction b()elle-même ne renvoie pas de valeur, l'appel retourne undefinedaprès tout autre travail effectué par 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
De toutes les réponses, j'ai plus aimé votre réponse en raison de sa simplicité.
anar khalilov

Bien placé! Très facile à comprendre cette réponse.
AndrewSteinheiser

Merci d'avoir validé le bit pour savoir si la fonction ne renvoie pas de valeur, l'appel renvoie undefined. J'ai découvert cette déconvenue récemment: même si la fonction renvoie explicitement null, si vous attribuez la valeur renvoyée à une variable, elle sera indéfinie, pas nulle. J'imagine que cela a causé beaucoup de problèmes étranges dans certaines bases de code, car null et undefined ne sont pas absolument équivalents avec ===.
Benjamin

37

return b(); appelle la fonction b () et renvoie son résultat.

return b; renvoie une référence à la fonction b, que vous pouvez stocker dans une variable pour appeler ultérieurement.


17

Le retour brenvoie un objet fonction. En Javascript, les fonctions ne sont que des objets, comme tout autre objet. Si vous ne trouvez pas cela utile, remplacez simplement le mot «objet» par «chose». Vous pouvez renvoyer n'importe quel objet d'une fonction. Vous pouvez renvoyer une valeur vrai / faux. Un entier (1,2,3,4 ...). Vous pouvez renvoyer une chaîne. Vous pouvez renvoyer un objet complexe avec plusieurs propriétés. Et vous pouvez renvoyer une fonction. une fonction est juste une chose.

Dans votre cas, retourner brenvoie la chose, la chose est une fonction appelable. Le retour b()renvoie la valeur renvoyée par la fonction appelable.

Considérez ce code:

function b() {
   return 42;
}

En utilisant la définition ci-dessus, return b();renvoie la valeur 42. D'autre part, return b;renvoie une fonction, qui elle-même renvoie la valeur de 42. Ce sont deux choses différentes.


4
il devrait revenir 42;)
c69

4

Lorsque vous revenez b, il s'agit simplement d'une référence à la fonction b, mais qui n'est pas exécutée pour le moment.

Lorsque vous revenez b(), vous exécutez la fonction et renvoyez sa valeur.

Essayez alerting typeof(s)dans vos exemples. L'extrait b vous donnera une «fonction». Qu'est-ce que l'extrait de code vous donnera?


Le premier donne «indéfini». Cela signifie-t-il que le retour b () est complètement inutile? De plus, dans le deuxième extrait de code, la fonction b est privée. Comment pouvons-nous alors accéder à la référence en dehors de la fonction? Veuillez me fournir un lien qui explique clairement ce concept si possible. Merci!
Cafecorridor

J'ai eu la réponse à la première. retourne 1 + 2 dans la fonction b () et le type de montre le nombre. Merci.
Cafecorridor

Je suis content que vous l'aillez compris! Quant à la fonction privée: elle n'est pas vraiment privée dans le deuxième exemple puisque vous l'avez déjà retournée. En fait, il est attribué à s. Essayez return thisau lieu de return bbien… Vous pourrez le faire s.b()alors;)
vzwick

Je vais l'essayer à coup sûr. Je n'ai pas encore atteint ce concept en Javascript. Peut-être dans quelques jours. Merci! :)
Cafecorridor

function a () {alert ("A!"); function b () {alert ("B!"); } return b; } var s = a (); supprimer un; s (); ---- fin ---- Le concept de référence en Javascript est-il le même qu'en Java? Ici, j'ai supprimé la fonction a () et pourtant un appel à s () exécute b (). Puis-je dire que s contient une copie de b et ne pointe pas vers b () défini dans a ()?
Cafecorridor

2

Imaginez la fonction comme un type, comme un int. Vous pouvez renvoyer des entiers dans une fonction. Vous pouvez également renvoyer des fonctions, ce sont des objets de type "fonction".

Maintenant le problème de syntaxe: parce que les fonctions renvoient des valeurs, comment pouvez-vous renvoyer une fonction et non pas une valeur?

en omettant les crochets! Parce que sans crochets, la fonction ne sera pas exécutée! Alors:

return b;

Renvoie la "fonction" (imaginez-le comme si vous renvoyez un nombre), tandis que:

return b();

Exécute d'abord la fonction puis retourne la valeur obtenue en l'exécutant, c'est une grosse différence!


Dans le deuxième extrait, la fonction b est privée. Comment pouvons-nous alors accéder à la référence en dehors de la fonction? Existe-t-il des règles régissant la même chose?
Cafecorridor

Les objets en JavaScript (cela inclut les fonctions) ne sont plus privés si vous les partagez.
kzh

@Cafecorridor: Si la fonction privée est retournée par quelque chose (une fonction publique) ou est affectée à une variable publique (enfin, une variable accessible par l'application), vous pouvez facilement faire yourvariable (); , sinon assignez la fonction retournée à une variable et recommencez yourvariable ();
Francesco Belladonna

2

Créez une variable :

var thing1 = undefined;

Déclarer une fonction :

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

Alertez la valeur de thing1(notre première variable):

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

Maintenant, si nous voulions thing1être une référence à la fonction something1, ce qui signifie que ce serait la même chose que notre fonction créée, nous ferions:

thing1 = something1;

Cependant, si nous voulions la return valeur de la fonction, nous devons lui attribuer la valeur de retour de la fonction exécutée. Vous exécutez la fonction en utilisant des parenthèses:

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

-1

Extrait un:

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'instruction 'b ()' signifie exécuter la fonction nommée 'b' qui montre une boîte de dialogue avec le texte 'B!'

l'instruction 'return b ();' signifie exécuter une fonction nommée 'b' et ensuite retourner quelle fonction 'b' retourne. mais 'b' ne renvoie rien, alors cette instruction 'return b ()' ne renvoie rien non plus. Si b () renvoie un nombre, alors 'return b ()' est également un nombre.

Maintenant 's' reçoit la valeur de ce que 'a ()' retourne, qui renvoie 'b ()', qui n'est rien, donc 's' n'est rien (en JavaScript c'est une chose en fait, c'est un 'indéfini'. lorsque vous demandez à JavaScript d'interpréter le type de données du 's', l'interpréteur JavaScript vous dira que 's' est indéfini.) Comme 's' est indéfini, lorsque vous demandez à JavaScript d'exécuter cette instruction 's ()', vous demandez à JavaScript d'exécuter une fonction nommée 's', mais 's' ici est un 'indéfini', pas une fonction, donc JavaScript se plaindra, "hé, s n'est pas une fonction, je ne sais pas comment à faire avec ce s ", alors un message d'erreur" Uncaught TypeError: s is not a function "sera affiché par JavaScript (testé dans Firefox et Chrome)


Extrait deux

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

maintenant, la fonction 'a' renvoyant un pointeur / alias vers une fonction nommée 'b'. donc quand exécuter 's = a ()', 's' obtiendra une valeur pointant vers b, c'est-à-dire que 's' est un alias de 'b' maintenant, appeler 's' équivaut à appeler 'b'. c'est-à-dire que «s» est une fonction maintenant. Exécuter 's ()' signifie exécuter la fonction 'b' (identique à l'exécution de 'b ()'), une boîte de dialogue affichant 'B!' apparaîtra (c'est-à-dire exécuter l'instruction 'alert (' B! '); dans la fonction' b ')


-2

C'est super utile dans la vraie vie.

Travailler avec Express.js

Donc, votre expressitinéraire régulier ressemble à ceci:

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

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

Mais que faire si vous avez besoin d'ajouter un wrapper, un gestionnaire d'erreurs ou un smth?

Ensuite, vous appelez votre fonction depuis 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 );
});

Ça a l'air compliqué? Eh bien, que diriez-vous de ceci:

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

Voyez à la fin que vous passez une fonction loggingWrapperayant un argument comme autre fonction itWorksHandler, et votre loggingWrapperretourne une nouvelle fonction qui prend req, res, nextcomme arguments.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.