Fonction imbriquée JavaScript

96

J'ai un morceau de code pour javascript que je ne comprends tout simplement pas:

function dmy(d) {
    function pad2(n) {
        return (n < 10) ? '0' + n : n;
    }

    return pad2(d.getUTCDate()) + '/' +
       pad2(d.getUTCMonth() + 1) + '/' +
       d.getUTCFullYear();
}

function outerFunc(base) {
    var punc = "!";

    //inner function
    function returnString(ext) {
       return base + ext + punc;
    }

    return returnString;
}

Comment définir une fonction dans une autre fonction? Pouvons-nous appeler pad2 () depuis l'extérieur de ma fonction ()?

Veuillez mettre un peu de lumière dessus. Merci

Thomas
la source
13
les fonctions peuvent être créées à l'intérieur des fonctions. C'est parfaitement valable.
0x499602D2

Réponses:

140

Les fonctions sont un autre type de variable en JavaScript (avec quelques nuances bien sûr). La création d'une fonction dans une autre fonction change la portée de la fonction de la même manière qu'elle changerait la portée d'une variable. Ceci est particulièrement important pour une utilisation avec des fermetures afin de réduire la pollution globale totale de l'espace de noms.

Les fonctions définies dans une autre fonction ne seront accessibles en dehors de la fonction que si elles ont été attachées à un objet accessible en dehors de la fonction:

function foo(doBar)
{
  function bar()
  {
    console.log( 'bar' );
  }

  function baz()
  {
    console.log( 'baz' );
  }

  window.baz = baz;
  if ( doBar ) bar();
}

Dans cet exemple, la fonction baz sera disponible pour une utilisation après l' fooexécution de la fonction, car elle est remplacée window.baz. La fonction de barre ne sera disponible dans aucun contexte autre que les étendues contenues dans la foofonction.

comme exemple différent:

function Fizz(qux)
{
  this.buzz = function(){
    console.log( qux );
  };
}

La Fizzfonction est conçue comme un constructeur afin que, lorsqu'elle est exécutée, elle affecte une buzzfonction à l'objet nouvellement créé.

zzzzBov
la source
Qu'est-ce que window.baz = baz? Pourquoi cette ligne m? Ke baz est-elle disponible?
Ziyang Zhang
@ZiyangZhang, le paragraphe après ce bloc de code a l'explication, y avait-il une partie particulière qui n'est pas claire?
zzzzBov
35

C'est ce qu'on appelle la fermeture .

Fondamentalement, la fonction définie dans une autre fonction n'est accessible que dans cette fonction. Mais peut être passé en conséquence et ce résultat peut être appelé.

C'est une fonctionnalité très puissante. Vous pouvez voir plus d'explications ici:

javascript_closures_for_dummies.html miroir sur Archive.org

Tadeck
la source
13
function x() {}

est équivalent (ou très similaire) à

var x = function() {}

à moins que je ne me trompe.

Il ne se passe donc rien de drôle.

Andreas
la source
8
La première syntaxe sera déplacée au début du document. il est donc possible d'appeler la fonction 'x' avant que la fonction ne soit initialisée.
Tom
10
La première syntaxe vous donnera également des traces de pile beaucoup plus agréables avec des fonctions nommées, la seconde vous donnera un mal de tête
TheZ
@TheZ Je pense que Chrome a récemment ajouté l'inférence de nom de fonction au débogage afin que vous n'ayez pas le même mal de tête qu'avant dans le cas courant.
jinglesthula
@jinglesthula Oui! Chrome a ajouté cette inférence de nom il y a quelque temps et c'est très apprécié :)
TheZ
10

L'instanciation de fonction est autorisée à l'intérieur et à l'extérieur des fonctions. À l'intérieur de ces fonctions, tout comme les variables, les fonctions imbriquées sont locales et ne peuvent donc pas être obtenues à partir de la portée extérieure.

function foo() {
    function bar() {
        return 1;
    }
    return bar();
}

foomanipule baren lui-même. barne peut pas être touché depuis la portée externe à moins qu'elle ne soit définie dans la portée externe.

Donc, cela ne fonctionnera pas:

function foo() {
    function bar() {
        return 1;
    }
}

bar(); // throws error: bar is not defined
0x499602D2
la source
4

Lorsque vous déclarez une fonction dans une fonction, les fonctions internes ne sont disponibles que dans la portée dans laquelle elles sont déclarées, ou dans votre cas, le pad2ne peut être appelé que dans ledmy portée.

Toutes les variables existantes dans dmysont visibles dans pad2, mais cela ne se produit pas dans l'autre sens: D

pedrochaves
la source
2

Il est parfaitement normal en Javascript (et dans de nombreux langages) d'avoir des fonctions à l'intérieur des fonctions.

Prenez le temps d'apprendre la langue, ne l'utilisez pas sous prétexte qu'elle ressemble à ce que vous savez déjà. Je suggérerais de regarder la série de présentations YUI de Douglas Crockford sur Javascript, avec un accent particulier sur l' acte III: Function the Ultimate (lien vers le téléchargement de la vidéo, les diapositives et la transcription)

Joaquim Rendeiro
la source
0

function foo() {
  function bar() {
    return 1;
  }
}
bar();

Jettera une erreur. Depuis barest défini à l'intérieur foo, barne sera accessible qu'à l'intérieur foo.
Pour l'utiliser, barvous devez l'exécuter à l'intérieur foo.

function foo() {
  function bar() {
    return 1;
  }
  bar();
}

Justin Liu
la source