Function in JavaScript that can be called only once

JavascriptFunctionDesign Patterns

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

Replace it with a reusable NOOP (no operation) function.

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

Solution 3 - Javascript

Point to an empty function once it has been called:

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>


Or, like so:

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)

Solution 4 - Javascript

UnderscoreJs has a function that does that, 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;
    };
  };

Solution 5 - Javascript

Talking about static variables, this is a little bit like closure variant:

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

once(); once(); 

You could then reset a function if you wish:

once.done = false;

Solution 6 - Javascript

You could simply have the function "remove itself"

​function Once(){
    console.log("run");

    Once = undefined;
}
    
Once();  // run
Once();  // Uncaught TypeError: undefined is not a function 

But this may not be the best answer if you don't want to be swallowing errors.

You could also do this:

function Once(){
    console.log("run");

    Once = function(){};
}
    
Once(); // run
Once(); // nothing happens

I need it to work like smart pointer, if there no elements from type A it can be executed, if there is one or more A elements the function can't be executed.

function Conditional(){
    if (!<no elements from type A>) return;

    // do stuff
}

Solution 7 - Javascript

var quit = false;

function something() {
    if(quit) {
       return;
    } 
    quit = true;
    ... other code....
}

Solution 8 - Javascript

try this

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

Solution 9 - Javascript

From some dude named Crockford... :)

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

Solution 10 - Javascript

Reusable invalidate function which works with 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);

Try it on JSBin: https://jsbin.com/vicipar/edit?js,console

Variation of answer from Bunyk

Solution 11 - Javascript

simple decorator that easy to write when you need

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

using:

var initializer= one( _ =>{
      console.log('initializing')
  })

initializer() // 'initializing'
initializer() // nop
initializer() // nop

Solution 12 - Javascript

Here is an example JSFiddle - http://jsfiddle.net/6yL6t/

And the code:

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();
    }
}

You could do:

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

And it will run only once :)

Solution 13 - Javascript

Initial setup:

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

Solution 14 - Javascript

If your using Node.js or writing JavaScript with browserify, consider the "once" npm module:

var once = require('once')

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

Solution 15 - Javascript

If you want to be able to reuse the function in the future then this works well based on ed Hopp's code above (I realize that the original question didn't call for this extra feature!):

   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();

The output look like:

Hello World!
Reset
Hello World!

Solution 16 - Javascript

A simple example for turning on light only once.

function turnOnLightOnce() {
  let lightOn = false;

  return function () {
    if (!lightOn) {
      console.log("Light is not on...Turning it on for first and last time");
      lightOn = true;
    }

  };
}

const lightOn = turnOnLightOnce();
lightOn()  // Light is not on...Turning it on for first and last time
lightOn()
lightOn()
lightOn()
lightOn()

https://codesandbox.io/s/javascript-forked-ojo0i?file=/index.js

This happens due to closure in JavaScript.

Solution 17 - Javascript

Trying to use underscore "once" function:

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

http://underscorejs.org/#once

Solution 18 - Javascript

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; */

Solution 19 - Javascript

if (!window.doesThisOnce){
  function myFunction() {
    // do something
    window.doesThisOnce = true;
  };
};

Solution 20 - Javascript

If you're using Ramda, you can use the function "once".

A quote from the documentation: > once Function (a… → b) → (a… → b) PARAMETERS Added in v0.1.0

> Accepts a function fn and returns a function that guards invocation of fn such that fn can only ever be called once, no matter how many times the returned function is invoked. The first value calculated is returned in subsequent invocations.

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

Solution 21 - Javascript

keep it as simple as possible

function sree(){
  console.log('hey');
  window.sree = _=>{};
}

You can see the result

script result

Solution 22 - Javascript

JQuery allows to call the function only once using the method one():

let func = function() {
  console.log('Calling just once!');
}
  
let elem = $('#example');
  
elem.one('click', func);

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <p>Function that can be called only once</p>
  <button id="example" >JQuery one()</button>
</div>

Implementation using JQuery method on():

let func = function(e) {
  console.log('Calling just once!');
  $(e.target).off(e.type, func)
}
  
let elem = $('#example');
  
elem.on('click', func);

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <p>Function that can be called only once</p>
  <button id="example" >JQuery on()</button>
</div>

Implementation using native JS:

let func = function(e) {
  console.log('Calling just once!');
  e.target.removeEventListener(e.type, func);
}
  
let elem = document.getElementById('example');
  
elem.addEventListener('click', func);

<div>
  <p>Functions that can be called only once</p>
  <button id="example" >ECMAScript addEventListener</button>
</div>

Solution 23 - Javascript

Tossing my hat in the ring for fun, added advantage of memoizing

const callOnce = (fn, i=0, memo) => () => i++ ? memo : (memo = fn());
// usage
const myExpensiveFunction = () => { return console.log('joe'),5; }
const memoed = callOnce(myExpensiveFunction);
memoed(); //logs "joe", returns 5
memoed(); // returns 5
memoed(); // returns 5
...

Solution 24 - Javascript

// This is how function in JavaScript can be called only once    

let started = false;     
      if (!started) {
                    start() { // "do something" }
                }
                started = true;
            }

Solution 25 - Javascript

This one is useful for preventing infinite loops (using jQuery):

<script>
var doIt = true;
if(doIt){
  // do stuff
  $('body').html(String($('body').html()).replace("var doIt = true;", 
                                                  "var doIt = false;"));
} 
</script>

If you're worried about namespace pollution, subsitute a long, random string for "doIt".

Solution 26 - Javascript

It helps to prevent sticky execution

var done = false;

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionvlio20View Question on Stackoverflow
Solution 1 - JavascriptTed HoppView Answer on Stackoverflow
Solution 2 - JavascriptI Hate LazyView Answer on Stackoverflow
Solution 3 - JavascriptvsyncView Answer on Stackoverflow
Solution 4 - JavascriptasawyerView Answer on Stackoverflow
Solution 5 - JavascriptBunykView Answer on Stackoverflow
Solution 6 - JavascriptShmiddtyView Answer on Stackoverflow
Solution 7 - JavascriptDiodeus - James MacFarlaneView Answer on Stackoverflow
Solution 8 - JavascriptDatabase_QueryView Answer on Stackoverflow
Solution 9 - JavascriptJowenView Answer on Stackoverflow
Solution 10 - JavascriptMonday FatigueView Answer on Stackoverflow
Solution 11 - Javascriptpery mimonView Answer on Stackoverflow
Solution 12 - JavascriptAldekeinView Answer on Stackoverflow
Solution 13 - JavascriptAndreas LouvView Answer on Stackoverflow
Solution 14 - JavascriptorcamanView Answer on Stackoverflow
Solution 15 - JavascriptCMPView Answer on Stackoverflow
Solution 16 - JavascriptSandeep AmarnathView Answer on Stackoverflow
Solution 17 - JavascriptAndrew FengView Answer on Stackoverflow
Solution 18 - JavascriptRegarBoyView Answer on Stackoverflow
Solution 19 - JavascriptatwView Answer on Stackoverflow
Solution 20 - JavascriptDavidView Answer on Stackoverflow
Solution 21 - JavascriptShreeketh KView Answer on Stackoverflow
Solution 22 - JavascriptNikitaView Answer on Stackoverflow
Solution 23 - JavascriptAdamView Answer on Stackoverflow
Solution 24 - JavascriptOmarsSaadeView Answer on Stackoverflow
Solution 25 - JavascriptElliot GorokhovskyView Answer on Stackoverflow
Solution 26 - JavascriptGleb DolzikovView Answer on Stackoverflow