I need to create a function which can be executed only once, in each time after the first it won’t be executed. I know from C++ and Java about static variables that can do the work but I would like to know if there is a more elegant way to do this?
Advertisement
Answer
If by “won’t be executed” you mean “will do nothing when called more than once”, you can create a closure:
var something = (function() { var executed = false; return function() { if (!executed) { executed = true; // do something } }; })(); something(); // "do something" happens something(); // nothing happens
In answer to a comment by @Vladloffe (now deleted): With a global variable, other code could reset the value of the “executed” flag (whatever name you pick for it). With a closure, other code has no way to do that, either accidentally or deliberately.
As other answers here point out, several libraries (such as Underscore and Ramda) have a little utility function (typically named once()
[*]) that accepts a function as an argument and returns another function that calls the supplied function exactly once, regardless of how many times the returned function is called. The returned function also caches the value first returned by the supplied function and returns that on subsequent calls.
However, if you aren’t using such a third-party library, but still want a utility function (rather than the nonce solution I offered above), it’s easy enough to implement. The nicest version I’ve seen is this one posted by David Walsh:
function once(fn, context) { var result; return function() { if (fn) { result = fn.apply(context || this, arguments); fn = null; } return result; }; }
I would be inclined to change fn = null;
to fn = context = null;
. There’s no reason for the closure to maintain a reference to context
once fn
has been called.
Usage:
function something() { /* do something */ } var one_something = once(something); one_something(); // "do something" happens one_something(); // nothing happens
[*] Be aware, though, that other libraries, such as this Drupal extension to jQuery, may have a function named once()
that does something quite different.