148 votes

Fonction en JavaScript qui ne peut être appelée qu'une seule fois

J'ai besoin de créer une fonction qui ne peut être exécutée qu'une seule fois, à chaque fois après la première, elle ne sera pas exécutée. Je connais, grâce au C++ et à Java, les variables statiques qui peuvent faire le travail, mais j'aimerais savoir s'il existe un moyen plus élégant de le faire ?

297voto

Ted Hopp Points 122617

Si par "ne sera pas exécuté" vous voulez dire "ne fera rien s'il est appelé plus d'une fois", vous pouvez créer une fermeture :

var something = (function() {
    var executed = false;
    return function() {
        if (!executed) {
            executed = true;
            // do something
        }
    };
})();

something(); // "do something" happens
something(); // nothing happens

En réponse à un commentaire de @Vladloffe (maintenant supprimé) : Avec une variable globale, un autre code pourrait réinitialiser la valeur de l'indicateur "exécuté" (quel que soit le nom que vous lui donnez). Avec une fermeture, un autre code n'a aucun moyen de le faire, que ce soit accidentellement ou délibérément.

Comme d'autres réponses ici le soulignent, plusieurs bibliothèques (telles que Underscore y Ramda ) ont une petite fonction d'utilité (généralement appelée once() [*] ) qui accepte une fonction comme argument et renvoie une autre fonction qui appelle la fonction fournie exactement une fois, quel que soit le nombre de fois où la fonction renvoyée est appelée. La fonction retournée met également en cache la valeur retournée en premier par la fonction fournie et la retourne lors des appels suivants.

Cependant, si vous n'utilisez pas une telle bibliothèque tierce, mais que vous voulez quand même une fonction utilitaire (plutôt que la solution nonce que j'ai proposée ci-dessus), elle est assez facile à mettre en œuvre. La plus belle version que j'ai vue est la suivante celui-ci a été posté par David Walsh :

function once(fn, context) { 
    var result;
    return function() { 
        if (fn) {
            result = fn.apply(context || this, arguments);
            fn = null;
        }
        return result;
    };
}

Je serais enclin à changer fn = null; a fn = context = null; . Il n'y a aucune raison pour que la fermeture maintienne une référence à context une fois fn a été appelé.

Utilisation :

function something() { /* do something */ }
var one_something = once(something);

one_something(); // "do something" happens
one_something(); // nothing happens

[*] Sachez cependant que d'autres bibliothèques, telles que <a href="https://www.drupal.org/node/444344" rel="noreferrer">cette extension Drupal de jQuery </a>peut avoir une fonction nommée <code>once()</code> qui fait quelque chose de tout à fait différent.

70voto

I Hate Lazy Points 18168

Remplacez-le par un NOOP réutilisable. (pas d'opération) fonction.

// this function does nothing
function noop() {};

function foo() {
    foo = noop; // swap the functions

    // do your thing
}

function bar() {
    bar = noop; // swap the functions

    // do your thing
}

46voto

vsync Points 11280

Pointer vers un vide une fois qu'elle a été appelée :

function myFunc(){
     myFunc = function(){}; // kill it as soon as it was called
     console.log('call once and never again!'); // your stuff here
};

<button onClick=myFunc()>Call myFunc()</button>

Ou, comme ça :

var myFunc = function func(){
     if( myFunc.fired ) return;
     myFunc.fired = true;
     console.log('called once and never again!'); // your stuff here
};

// even if referenced & "renamed"
((refToMyfunc)=>{
  setInterval(refToMyfunc, 1000);
})(myFunc)

25voto

asawyer Points 10642

UnderscoreJs a une fonction qui fait cela, underscorejs.org/#once

  // Returns a function that will be executed at most one time, no matter how
  // often you call it. Useful for lazy initialization.
  _.once = function(func) {
    var ran = false, memo;
    return function() {
      if (ran) return memo;
      ran = true;
      memo = func.apply(this, arguments);
      func = null;
      return memo;
    };
  };

12voto

Bunyk Points 924

En ce qui concerne les variables statiques, c'est un peu comme la variante de fermeture :

var once = function() {
    if(once.done) return;
    console.log('Doing this once!');
    once.done = true;
};

once(); once(); 

Vous pouvez alors réinitialiser une fonction si vous le souhaitez :

once.done = false;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X