web-dev-qa-db-fra.com

Fermetures JavaScript vs fonctions anonymes

Un de mes amis et moi discutons actuellement de ce qui constitue une fermeture de JS et de ce qui ne l’est pas. Nous voulons simplement nous assurer de bien comprendre le problème.

Prenons cet exemple. Nous avons une boucle de comptage et voulons imprimer la variable de compteur sur la console en différé. Par conséquent, nous utilisons setTimeout et fermetures pour capturer la valeur de la variable counter afin de s’assurer qu’elle n’imprimera pas N fois la valeur N.

La mauvaise solution sans fermetures ou tout ce qui est proche de fermetures serait:

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}

qui imprimera bien sûr 10 fois la valeur de i après la boucle, à savoir 10.

Sa tentative était donc:

for(var i = 0; i < 10; i++) {
    (function(){
        var i2 = i;
        setTimeout(function(){
            console.log(i2);
        }, 1000)
    })();
}

impression 0 à 9 comme prévu.

Je lui ai dit qu'il n'utilisait pas un fermeture pour capturer i, mais il insiste pour dire qu'il l'est. J'ai prouvé qu'il n'utilisait pas fermetures en plaçant le corps de la boucle for dans un autre setTimeout (en passant sa fonction anonyme à setTimeout), en imprimant à nouveau 10 fois. Il en va de même si je stocke sa fonction dans un var et l'exécute après la boucle, en imprimant également 10 fois 10. Mon argument est donc que il ne capture pas vraiment ) la valeur de i, rendant sa version pas une fermeture.

Ma tentative était:

for(var i = 0; i < 10; i++) {
    setTimeout((function(i2){
        return function() {
            console.log(i2);
        }
    })(i), 1000);
}

Donc, je capture i (nommé i2 dans la fermeture), mais maintenant je renvoie une autre fonction et le passe. Dans mon cas, la fonction passée à setTimeout capture vraiment i.

Maintenant, qui utilise les fermetures et qui ne le fait pas?

Notez que les deux solutions affichent une impression différée de 0 à 9 sur la console, elles résolvent donc le problème initial, mais nous souhaitons savoir laquelle de ces deux solutions tilise des fermetures pour ce faire.

547
leemes

Note de l'éditeur: Toutes les fonctions en JavaScript sont des fermetures, comme expliqué dans ce post . Cependant, nous ne souhaitons identifier qu'un sous-ensemble de ces fonctions qui sont intéressant d'un point de vue théorique. Désormais, toute référence au mot fermeture fera référence à ce sous-ensemble de fonctions, sauf indication contraire.

Une explication simple pour les fermetures:

  1. Prendre une fonction. Appelons ça F.
  2. Lister toutes les variables de F.
  3. Les variables peuvent être de deux types:
    1. Variables locales (variables liées)
    2. Variables non locales (variables libres)
  4. Si F n'a pas de variables libres, il ne peut s'agir d'une fermeture.
  5. Si F a des variables libres (définies dans , une portée parent de F), alors:
    1. Il ne doit exister qu'un seul domaine parent de F auquel une variable libre est liée.
    2. Si F est référencé depuis l'extérieur que l'étendue parent , il devient alors un fermeture pour cette variable libre.
    3. Cette variable libre est appelée valeur à la hausse de la fermeture F.

Utilisons maintenant ceci pour déterminer qui utilise les fermetures et qui ne les utilise pas (pour des raisons d’explication, j’ai nommé les fonctions):

Cas 1: Le programme de votre ami

for (var i = 0; i < 10; i++) {
    (function f() {
        var i2 = i;
        setTimeout(function g() {
            console.log(i2);
        }, 1000);
    })();
}

Dans le programme ci-dessus, il y a deux fonctions: f et g. Voyons si ce sont des fermetures:

Pour f:

  1. Énumérer les variables:
    1. i2 est une variable locale .
    2. i est une variable libre .
    3. setTimeout est une variable libre .
    4. g est une variable locale .
    5. console est une variable libre .
  2. Recherchez la portée parente à laquelle chaque variable libre est liée:
    1. i est lié à la portée globale.
    2. setTimeout est lié à la portée globale.
    3. console est lié à la portée globale.
  3. Dans quelle portée la fonction est-elle référencée ? La portée globale .
    1. Par conséquent, i n'est pas fermé sur par f.
    2. Par conséquent, setTimeout n'est pas fermé sur par f.
    3. Par conséquent, console n'est pas fermé sur par f.

Ainsi, la fonction f n'est pas une fermeture.

Pour g:

  1. Énumérer les variables:
    1. console est une variable libre .
    2. i2 est une variable libre .
  2. Recherchez la portée parente à laquelle chaque variable libre est liée:
    1. console est lié à la portée globale.
    2. i2 est lié à la portée de f.
  3. Dans quelle portée la fonction est-elle référencée ? La portée de setTimeout.
    1. Par conséquent, console n'est pas fermé sur par g.
    2. Ainsi, i2 est fermé sur par g.

Ainsi, la fonction g est une fermeture pour la variable libre i2 (qui est une valeur à la hausse pour g) lorsque il est référencé depuis setTimeout.

Mauvais pour vous: Votre ami utilise une fermeture. La fonction interne est une fermeture.

Cas 2: Votre programme

for (var i = 0; i < 10; i++) {
    setTimeout((function f(i2) {
        return function g() {
            console.log(i2);
        };
    })(i), 1000);
}

Dans le programme ci-dessus, il y a deux fonctions: f et g. Voyons si ce sont des fermetures:

Pour f:

  1. Énumérer les variables:
    1. i2 est une variable locale .
    2. g est une variable locale .
    3. console est une variable libre .
  2. Recherchez la portée parente à laquelle chaque variable libre est liée:
    1. console est lié à la portée globale.
  3. Dans quelle portée la fonction est-elle référencée ? La portée globale .
    1. Par conséquent, console n'est pas fermé sur par f.

Ainsi, la fonction f n'est pas une fermeture.

Pour g:

  1. Énumérer les variables:
    1. console est une variable libre .
    2. i2 est une variable libre .
  2. Recherchez la portée parente à laquelle chaque variable libre est liée:
    1. console est lié à la portée globale.
    2. i2 est lié à la portée de f.
  3. Dans quelle portée la fonction est-elle référencée ? La portée de setTimeout.
    1. Par conséquent, console n'est pas fermé sur par g.
    2. Ainsi, i2 est fermé sur par g.

Ainsi, la fonction g est une fermeture pour la variable libre i2 (qui est une valeur à la hausse pour g) lorsque il est référencé depuis setTimeout.

Tant mieux pour vous: Vous utilisez une fermeture. La fonction interne est une fermeture.

Donc, vous et votre ami utilisez tous les deux des fermetures. Arrêter de se disputer. J'espère que j'ai clarifié le concept de fermeture et comment les identifier pour vous deux.

Edit: Une explication simple sur la raison pour laquelle toutes les fonctions sont fermées (crédits @Peter):

Considérons d’abord le programme suivant (c’est le control ):

lexicalScope();

function lexicalScope() {
    var message = "This is the control. You should be able to see this message being alerted.";

    regularFunction();

    function regularFunction() {
        alert(eval("message"));
    }
}
  1. Nous savons que lexicalScope et regularFunction ne sont pas des fermetures de la définition ci-dessus .
  2. Lorsque nous exécutons le programme , nous nous attendons à ce que message soit alerté car regularFunction n’est pas une fermeture (c’est-à-dire qu’il a accès à toutes les variables dans son champ parent, y compris message) .
  3. Lorsque nous exécutons le programme , nous observons que message est bien alerté.

Ensuite, considérons le programme suivant (c'est le alternative ):

var closureFunction = lexicalScope();

closureFunction();

function lexicalScope() {
    var message = "This is the alternative. If you see this message being alerted then in means that every function in JavaScript is a closure.";

    return function closureFunction() {
        alert(eval("message"));
    };
}
  1. Nous savons que seulement closureFunction est une fermeture de la définition ci-dessus .
  2. Lorsque nous exécutons le programme , nous nous attendons à ce que message ne soit pas alerté car closureFunction est une fermeture (c'est-à-dire qu'il n'a accès qu'à toutes ses variables non locales à l'heure de création de la fonction ( voir cette réponse ) - cela n'inclut pas message).
  3. Lorsque nous exécutons le programme , nous observons que message est en train d'être alerté.

Qu'en déduis-on?

  1. Les interprètes JavaScript ne traitent pas les fermetures de la même manière que les autres fonctions.
  2. Chaque fonction porte sa chaîne de portée avec elle. Les fermetures n'ont pas d'environnement de référencement séparé .
  3. Une fermeture est comme toutes les autres fonctions. Nous les appelons simplement des fermetures quand elles sont référencées dans une portée en dehors de le portée à laquelle ils appartiennent parce que il s’agit d’un cas intéressant.
639
Aadit M Shah

Selon la closure définition:

Une "fermeture" est une expression (généralement une fonction) pouvant avoir variables libres avec un environnement qui lie ces variables (qui "ferment" l'expression).

Vous utilisez closure si vous définissez une fonction utilisant une variable définie en dehors de la fonction. (on appelle la variable a variable libre).
Ils utilisent tous closure (même dans le premier exemple).

94
kev

En un mot Javascript Closures autoriser une fonction à accéder à une variable c'est-à-dire déclaré dans une fonction lexical-parent.

Voyons une explication plus détaillée. Pour comprendre les fermetures, il est important de comprendre comment JavaScript utilise les variables.

Scopes

En JavaScript, les étendues sont définies avec des fonctions. Chaque fonction définit une nouvelle portée.

Considérez l'exemple suivant.

function f()
{//begin of scope f
  var foo='hello'; //foo is declared in scope f
  for(var i=0;i<2;i++){//i is declared in scope f
     //the for loop is not a function, therefore we are still in scope f
     var bar = 'Am I accessible?';//bar is declared in scope f
     console.log(foo);
  }
  console.log(i);
  console.log(bar);
}//end of scope f

appeler f imprime

hello
hello
2
Am I Accessible?

Considérons maintenant le cas où nous avons une fonction g définie dans une autre fonction f.

function f()
{//begin of scope f
  function g()
  {//being of scope g
    /*...*/
  }//end of scope g
  /*...*/
}//end of scope f

Nous appellerons f le parent lexical de g. Comme expliqué précédemment, nous avons maintenant 2 portées; la portée f et la portée g.

Mais une portée est "dans" l'autre portée, la portée de la fonction enfant fait-elle partie de la portée de la fonction parent? Que se passe-t-il avec les variables déclarées dans l'étendue de la fonction parent? vais-je pouvoir y accéder depuis la portée de la fonction enfant? C'est exactement là que les fermetures interviennent.

Fermetures

En JavaScript, la fonction g peut non seulement accéder aux variables déclarées dans l'étendue g, mais également à toutes les variables déclarées dans l'étendue de la fonction parente f.

Pensez à suivre;

function f()//lexical parent function
{//begin of scope f
  var foo='hello'; //foo declared in scope f
  function g()
  {//being of scope g
    var bar='bla'; //bar declared in scope g
    console.log(foo);
  }//end of scope g
  g();
  console.log(bar);
}//end of scope f

appeler f imprime

hello
undefined

Regardons la ligne console.log(foo);. À ce stade, nous sommes dans le domaine g et nous essayons d'accéder à la variable foo déclarée dans le domaine f. Mais comme indiqué précédemment, nous pouvons accéder à toute variable déclarée dans une fonction parent lexicale, ce qui est le cas ici; g est le parent lexical de f. Par conséquent, hello est imprimé.
Regardons maintenant la ligne console.log(bar);. À ce stade, nous sommes dans le domaine f et nous essayons d'accéder à la variable bar déclarée dans le domaine g. bar n'est pas déclaré dans l'étendue actuelle et la fonction g n'est pas le parent de f, donc bar n'est pas défini.

En réalité, nous pouvons également accéder aux variables déclarées dans le cadre d'une fonction lexicale "grand parent". Donc, s'il y aurait une fonction h définie dans la fonction g

function f()
{//begin of scope f
  function g()
  {//being of scope g
    function h()
    {//being of scope h
      /*...*/
    }//end of scope h
    /*...*/
  }//end of scope g
  /*...*/
}//end of scope f

alors h pourrait accéder à toutes les variables déclarées dans l'étendue de la fonction h, g et f. Ceci est fait avec fermetures. En JavaScript fermetures nous permet d’accéder à toute variable déclarée dans la fonction parent lexicale, dans la fonction grand parent lexical, dans la fonction grand-grand-parent lexical, etc. Ceci peut être vu comme un chaîne de la portée; scope of current function -> scope of lexical parent function -> scope of lexical grand parent function -> ... jusqu'à la dernière fonction parente qui n'a pas de parent lexical.

l'objet window

En réalité, la chaîne ne s’arrête pas à la dernière fonction parent. Il y a une autre portée spéciale; le portée globale. Toute variable non déclarée dans une fonction est considérée comme déclarée dans la portée globale. La portée mondiale a deux spécialités;

  • chaque variable déclarée dans la portée globale est accessible partout
  • les variables déclarées dans la portée globale correspondent aux propriétés de l'objet window.

Par conséquent, il existe exactement deux manières de déclarer une variable foo dans la portée globale; soit en ne le déclarant pas dans une fonction, soit en définissant la propriété foo de l'objet window.

Les deux tentatives utilisent des fermetures

Maintenant que vous avez lu une explication plus détaillée, il est maintenant évident que les deux solutions utilisent des fermetures. Mais pour être sûr, faisons une preuve.

Créons un nouveau langage de programmation; JavaScript-No-Closure. Comme son nom l'indique, JavaScript-No-Closure est identique à JavaScript, à la différence qu'il ne prend pas en charge les fermetures.

En d'autres termes;

var foo = 'hello';
function f(){console.log(foo)};
f();
//JavaScript-No-Closure prints undefined
//JavaSript prints hello

Bon, voyons ce qui se passe avec la première solution avec JavaScript-No-Closure;

for(var i = 0; i < 10; i++) {
  (function(){
    var i2 = i;
    setTimeout(function(){
        console.log(i2); //i2 is undefined in JavaScript-No-Closure 
    }, 1000)
  })();
}

par conséquent, ceci imprimera undefined 10 fois dans JavaScript-No-Closure.

La première solution utilise donc la fermeture.

Regardons la deuxième solution.

for(var i = 0; i < 10; i++) {
  setTimeout((function(i2){
    return function() {
        console.log(i2); //i2 is undefined in JavaScript-No-Closure
    }
  })(i), 1000);
}

par conséquent, ceci imprimera undefined 10 fois dans JavaScript-No-Closure.

Les deux solutions utilisent des fermetures.

Edit: On suppose que ces 3 extraits de code ne sont pas définis dans la portée globale. Sinon, les variables foo et i seraient liées à l'objet window et donc accessibles via l'objet window en JavaScript et en JavaScript-No-Closure.

50
brillout

Je n'ai jamais été content de la façon dont quelqu'un l'explique.

La clé pour comprendre les fermetures consiste à comprendre à quoi ressemblerait un SC sans des fermetures.

Sans fermetures, cela jetterait une erreur

function outerFunc(){
    var outerVar = 'an outerFunc var';
    return function(){
        alert(outerVar);
    }
}

outerFunc()(); //returns inner function and fires it

Une fois que outerFunc est revenu dans une version imaginaire de JavaScript à fermeture désactivée, la référence à outerVar serait récupérée et disparue, ne laissant rien là-bas pour la fonction interne à référencer.

Les fermetures sont essentiellement les règles spéciales qui permettent à ces vars d'exister lorsqu'une fonction interne référence les variables d'une fonction externe. Avec les fermetures, les vars référencés sont conservés même après la fin de la fonction externe ou "fermés" si cela vous aide à vous rappeler le point.

Même avec les fermetures, le cycle de vie des vars locaux dans une fonction sans fonctions internes faisant référence à ses locaux fonctionne de la même manière que dans une version sans fermeture. Lorsque la fonction est terminée, les habitants sont récupérés.

Une fois que vous avez une référence dans une fonction interne à une variable externe, elle ressemble toutefois à un joint de porte qui est placé dans le chemin de la récupération de place pour les vars référencés.

Une façon peut-être plus précise d'examiner les fermetures est que la fonction interne utilise fondamentalement la portée interne comme sa propre définition de portée.

Mais le contexte référencé est en fait persistant et ne ressemble pas à un instantané. Le déclenchement répété d'une fonction interne renvoyée qui incrémente et enregistre en continu la variable locale d'une fonction externe continuera à alerter des valeurs plus élevées.

function outerFunc(){
    var incrementMe = 0;
    return function(){ incrementMe++; console.log(incrementMe); }
}
var inc = outerFunc();
inc(); //logs 1
inc(); //logs 2
22
Erik Reppen

Vous utilisez tous les deux des fermetures.

Je vais avec le définition Wikipedia ici:

En informatique, une fermeture (également fermeture lexicale ou fermeture de fonction) est une fonction ou une référence à une fonction ainsi qu’un environnement de référencement: une table stockant une référence à chacune des variables non locales (également appelées variables libres) de cette fonction. . Une fermeture (contrairement à un pointeur de fonction simple) permet à une fonction d'accéder à ces variables non locales même lorsqu'elles sont appelées en dehors de son étendue lexicale immédiate.

La tentative de votre ami utilise clairement la variable i, qui est non locale, en prenant sa valeur et en faisant une copie à stocker dans le i2 local.

Votre propre tentative transmet i (qui est dans la portée du site d’appel) à une fonction anonyme en tant qu’argument. Ce n'est pas une fermeture jusqu'à présent, mais cette fonction retourne une autre fonction qui fait référence au même i2. Dans la fonction anonyme interne, i2 n'est pas local, cela crée une fermeture.

17
Jon

Vous et votre ami utilisez tous les deux des fermetures:

Une fermeture est un type d’objet particulier qui combine deux éléments: une fonction et l’environnement dans lequel cette fonction a été créée. L'environnement est constitué de toutes les variables locales qui étaient dans la portée au moment de la création de la fermeture.

MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures

Dans le code de votre ami, la fonction function(){ console.log(i2); } est définie à l'intérieur de la fermeture de la fonction anonyme function(){ var i2 = i; ... et peut lire/écrire une variable locale i2.

Dans votre code, la fonction function(){ console.log(i2); } est définie à l'intérieur de la fermeture de la fonction function(i2){ return ... et peut lire/écrire de la valeur locale i2 ( déclarée dans ce cas en tant que paramètre).

Dans les deux cas, la fonction function(){ console.log(i2); } est ensuite transmise à setTimeout.

Un autre équivalent (mais avec une utilisation moindre de la mémoire) est:

_function fGenerator(i2){
    return function(){
        console.log(i2);
    }
}
for(var i = 0; i < 10; i++) {
    setTimeout(fGenerator(i), 1000);
}
_
13
Andrew D.

Regardons les deux manières:

(function(){
    var i2 = i;
    setTimeout(function(){
        console.log(i2);
    }, 1000)
})();

Déclare et exécute immédiatement une fonction anonyme qui exécute setTimeout() dans son propre contexte. La valeur actuelle de i est préservée en effectuant une copie dans i2 first; cela fonctionne à cause de l'exécution immédiate.

setTimeout((function(i2){
    return function() {
        console.log(i2);
    }
})(i), 1000);

Déclare un contexte d'exécution pour la fonction interne dans lequel la valeur actuelle de i est conservée dans i2; Cette approche utilise également l'exécution immédiate pour préserver la valeur.

Important

Il convient de mentionner que la sémantique de la série n'est PAS la même entre les deux approches; votre fonction interne est passée à setTimeout() alors que sa fonction interne appelle setTimeout() lui-même.

Envelopper les deux codes dans un autre setTimeout() ne prouve pas que seule la seconde approche utilise des fermetures, il n'y a tout simplement pas la même chose pour commencer.

Conclusion

Les deux méthodes utilisent des fermetures, donc cela revient à un goût personnel; la deuxième approche est plus facile à "déplacer" ou à généraliser.

10
Ja͢ck

fermeture

Une fermeture n'est pas une fonction ni une expression. Il doit être vu comme une sorte de "capture instantanée" des variables utilisées en dehors de functionscope et utilisée dans la fonction. Grammaticalement, on devrait dire: 'prenez la fermeture des variables'.

Encore une fois, en d'autres termes: une fermeture est une copie du contexte pertinent des variables dont dépend la fonction.

Encore une fois (naïf): Une fermeture a accès à des variables qui ne sont pas passées en paramètre.

N'oubliez pas que ces concepts fonctionnels dépendent fortement du langage/environnement de programmation que vous utilisez. En JavaScript, la fermeture dépend de la portée lexicale (ce qui est vrai dans la plupart des langages c).

Ainsi, renvoyer une fonction revient généralement à renvoyer une fonction anonyme/non nommée. Lorsque les variables d'accès à la fonction, non passées en tant que paramètre, et dans son étendue (lexicale), une fermeture a été effectuée.

Donc, concernant vos exemples:

// 1
for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i); // closure, only when loop finishes within 1000 ms,
    }, 1000);           // i = 10 for all functions
}
// 2
for(var i = 0; i < 10; i++) {
    (function(){
        var i2 = i; // closure of i (lexical scope: for-loop)
        setTimeout(function(){
            console.log(i2); // closure of i2 (lexical scope:outer function)
        }, 1000)
    })();
}
// 3
for(var i = 0; i < 10; i++) {
    setTimeout((function(i2){
        return function() {
            console.log(i2); // closure of i2 (outer scope)

        }
    })(i), 1000); // param access i (no closure)
}

Tous utilisent des fermetures. Ne confondez pas le point d'exécution avec les fermetures. Si le "cliché" des fermetures est pris au mauvais moment, les valeurs peuvent être inattendues, mais une fermeture est certainement prise!

10
Andries

J'ai écrit ceci il y a quelque temps pour me rappeler ce qu'est une fermeture et comment cela fonctionne dans JS.

Une fermeture est une fonction qui, lorsqu'elle est appelée, utilise la portée dans laquelle elle a été déclarée, et non la portée dans laquelle elle a été appelée. En javaScript, toutes les fonctions se comportent comme ceci. Les valeurs de variable dans une étendue persistent tant qu'il existe une fonction qui les désigne toujours. L'exception à la règle est 'this', qui fait référence à l'objet dans lequel se trouve la fonction lorsqu'elle est appelée.

var z = 1;
function x(){
    var z = 2; 
    y(function(){
      alert(z);
    });
}
function y(f){
    var z = 3;
    f();
}
x(); //alerts '2' 
8
Nat Darke

Après une inspection minutieuse, on dirait que vous utilisez tous les deux la fermeture.

Dans le cas de vos amis, vous accédez à i à l'intérieur de la fonction anonyme 1 et à i2 à la fonction anonyme 2 où le console.log est présent.

Dans votre cas, vous accédez à i2 dans une fonction anonyme où console.log est présent. Ajoutez une instruction debugger; avant console.log et dans les outils de développement chrome sous "Variables de champ", il indique dans quel champ se trouve la variable.

6
Ramesh

Considérer ce qui suit. Cela crée et recrée une fonction f qui se ferme sur i, mais différentes!

i=100;

f=function(i){return function(){return ++i}}(0);
alert([f,f(),f(),f(),f(),f(),f(),f(),f(),f(),f()].join('\n\n'));

f=function(i){return new Function('return ++i')}(0);        /*  function declarations ~= expressions! */
alert([f,f(),f(),f(),f(),f(),f(),f(),f(),f(),f()].join('\n\n'));

alors que ce qui suit se ferme sur "une" fonction "elle-même"
(l'extrait suivant utilise un seul référent f)

for(var i = 0; i < 10; i++) {
    setTimeout( new Function('console.log('+i+')'),  1000 );
}

ou pour être plus explicite:

for(var i = 0; i < 10; i++) {
    console.log(    f = new Function( 'console.log('+i+')' )    );
    setTimeout( f,  1000 );
}

NB la dernière définition de f est function(){ console.log(9) } avant que 0 soit imprimé.

Caveat! Le concept de fermeture peut être une distraction coercitive de l'essence de la programmation élémentaire:

for(var i = 0; i < 10; i++) {     setTimeout( 'console.log('+i+')',  1000 );      }

x-refs .:
Comment fonctionnent les fermetures de JavaScript?
Explication sur les fermetures javascript
ne fermeture (JS) nécessite-t-elle une fonction dans une fonction
Comment comprendre les fermetures en Javascript?
Confusion variable locale et globale avec Javascript

4
ekim

Je voudrais partager mon exemple et une explication sur les fermetures. J'ai créé un exemple python et deux figures pour illustrer les états de pile.

def maker(a, b, n):
    margin_top = 2
    padding = 4
    def message(msg):
        print('\n’ * margin_top, a * n, 
            ' ‘ * padding, msg, ' ‘ * padding, b * n)
    return message

f = maker('*', '#', 5)
g = maker('', '♥’, 3)
…
f('hello')
g(‘good bye!')

La sortie de ce code serait la suivante:

*****      hello      #####

      good bye!    ♥♥♥

Voici deux figures pour montrer les piles et la fermeture attachée à l'objet de fonction.

lorsque la fonction est renvoyée par le fabricant

lorsque la fonction est appelée plus tard

Lorsque la fonction est appelée via un paramètre ou une variable non locale, le code nécessite des liaisons de variable locales telles que margin_top, padding ainsi que a, b, n. Afin de garantir le bon fonctionnement du code de fonction, le cadre de pile de la fonction maker qui avait disparu depuis longtemps devrait être accessible, ce qui est sauvegardé dans la fermeture que nous pouvons trouver avec l'objet message de fonction.

0
Eunjung Lee