Funzione in javascript che può essere chiamata solo una volta

Ho bisogno di creare una funzione che può essere eseguita solo una volta, in ogni momento dopo la prima non verrà eseguita. So da C ++ e Java su variabili statiche che possono fare il lavoro, ma mi piacerebbe sapere se c’è un modo più elegante per fare questo?

Se per “non verrà eseguito” intenderai “non farà nulla se chiamato più di una volta”, puoi creare una chiusura:

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

In risposta a un commento di @Vladloffe (ora cancellato): con una variabile globale, un altro codice potrebbe reimpostare il valore del flag “eseguito” (qualunque nome tu scelga per esso). Con una chiusura, l’altro codice non ha modo di farlo, accidentalmente o deliberatamente.

Come indicano altre risposte, diverse librerie (come Underscore e Ramda ) hanno una piccola funzione di utilità (tipicamente chiamata once() [*] ) che accetta una funzione come argomento e restituisce un’altra funzione che chiama la funzione fornita esattamente una volta, indipendentemente da quante volte viene chiamata la funzione restituita. La funzione restituita memorizza inoltre nella cache il valore restituito per primo dalla funzione fornita e lo restituisce nelle chiamate successive.

Tuttavia, se non si utilizza tale libreria di terze parti, ma si desidera comunque una funzione di utilità (piuttosto che la soluzione nonce che ho proposto sopra), è abbastanza facile da implementare. La versione più bella che ho visto è questa pubblicata da David Walsh :

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

[*] Attenzione, però, che altre librerie, come questa estensione Drupal a jQuery , possono avere una funzione chiamata once() che fa qualcosa di completamente diverso.

Sostituirlo con una funzione NOOP riutilizzabile (nessuna operazione) .

 // 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 } 

UnderscoreJs ha una funzione che lo fa, 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; }; }; 

Basta puntare a una funzione vuota dopo che è stata chiamata.

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

Parlando di variabili statiche, questo è un po ‘come la variante di chiusura:

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

È quindi ansible ripristinare una funzione se lo si desidera:

 once.done = false; 
 var quit = false; function something() { if(quit) { return; } quit = true; ... other code.... } 

Potresti semplicemente avere la funzione “rimuovi se stessa”

 ​function Once(){ console.log("run"); Once = undefined; } Once(); // run Once(); // Uncaught TypeError: undefined is not a function 

Ma questa potrebbe non essere la migliore risposta se non si vogliono inghiottire errori.

Puoi anche fare questo:

 function Once(){ console.log("run"); Once = function(){}; } Once(); // run Once(); // nothing happens 

Ho bisogno che funzioni come un puntatore intelligente, se non ci sono elementi dal tipo A che può essere eseguito, se c’è uno o più elementi A la funzione non può essere eseguita.

 function Conditional(){ if (!) return; // do stuff } 

prova questo

 var fun = (function() { var called = false; return function() { if (!called) { console.log("I called"); called = true; } } })() 

Da un tizio di nome Crockford … 🙂

 function once(func) { return function () { var f = func; func = null; return f.apply( this, arguments ); }; } 

Ecco un esempio di JSFiddle – http://jsfiddle.net/6yL6t/

E il codice:

 function hashCode(str) { var hash = 0, i, chr, len; if (str.length == 0) return hash; for (i = 0, len = str.length; i < len; i++) { chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return hash; } var onceHashes = {}; function once(func) { var unique = hashCode(func.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1]); if (!onceHashes[unique]) { onceHashes[unique] = true; func(); } } 

Potresti fare:

 for (var i=0; i<10; i++) { once(function() { alert(i); }); } 

E funzionerà solo una volta 🙂

Configurazione iniziale:

 var once = function( once_fn ) { var ret, is_called; // return new function which is our control function // to make sure once_fn is only called once: return function(arg1, arg2, arg3) { if ( is_called ) return ret; is_called = true; // return the result from once_fn and store to so we can return it multiply times: // you might wanna look at Function.prototype.apply: ret = once_fn(arg1, arg2, arg3); return ret; }; } 

Se usi Node.js o scrivi JavaScript con browserify, considera il modulo “una volta” npm :

 var once = require('once') function load (file, cb) { cb = once(cb) loader.load('file') loader.once('load', cb) loader.once('error', cb) } 

Funzione invalidate riutilizzabile che funziona con setInterval :

 var myFunc = function (){ if (invalidate(arguments)) return; console.log('called once and never again!'); // your stuff here }; const invalidate = function(a) { var fired = a.callee.fired; a.callee.fired = true; return fired; } setInterval(myFunc, 1000); 

Provalo su JSBin: https://jsbin.com/vicipar/edit?js,console

Variazione della risposta di Bunyk

Se vuoi essere in grado di riutilizzare la funzione in futuro, allora funziona bene sulla base del codice di Hopp sopra (mi rendo conto che la domanda originale non richiedeva questa caratteristica extra!):

  var something = (function() { var executed = false; return function(value) { // if an argument is not present then if(arguments.length == 0) { if (!executed) { executed = true; //Do stuff here only once unless reset console.log("Hello World!"); } else return; } else { // otherwise allow the function to fire again executed = value; return; } } })(); something();//Hello World! something(); something(); console.log("Reset"); //Reset something(false); something();//Hello World! something(); something(); 

L’output è simile a:

 Hello World! Reset Hello World! 

Cercando di usare la sottolineatura “una volta”:

 var initialize = _.once(createApplication); initialize(); initialize(); // Application is only created once. 

http://underscorejs.org/#once

 var init = function() { console.log("logges only once"); init = false; }; if(init) { init(); } /* next time executing init() will cause error because now init is -equal to false, thus typing init will return false; */ 

Se stai usando Ramda, puoi usare la funzione “una volta” .

Una citazione dalla documentazione:

una volta Funzione (a … → b) → (a … → b) PARAMETRI Aggiunto in v0.1.0

Accetta una funzione fn e restituisce una funzione che protegge la chiamata di fn in modo tale che fn possa essere sempre chiamata una sola volta, indipendentemente da quante volte viene invocata la funzione restituita. Il primo valore calcolato viene restituito nelle successive chiamate.

 var addOneOnce = R.once(x => x + 1); addOneOnce(10); //=> 11 addOneOnce(addOneOnce(50)); //=> 11 

Vengo con un semplice decoratore che risolve il tuo problema facilmente

 function one(func) { return function () { func && func.apply(this, arguments); func = null; } } 

utilizzando:

 var initializer= one( _ =>{ console.log('initializing') }) initializer() // 'initializing' initializer() // nop initializer() // nop 
 if (!window.doesThisOnce){ function myFunction() { // do something window.doesThisOnce = true; }; }; 

Questo è utile per prevenire loop infiniti (usando jQuery):

  

Se sei preoccupato dell’inquinamento dello spazio dei nomi, sostituisci una stringa lunga e casuale per “doIt”.

Aiuta a prevenire l’esecuzione appiccicosa

 var done = false; function doItOnce(func){ if(!done){ done = true; func() } setTimeout(function(){ done = false; },1000) }