Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a 'once' function in JavaScript

I have this spec from Jasmine.js which tests a once function. I'm not sure how to implement such a function though.

/* Functions that decorate other functions.  These functions return a version of the function
   with some changed behavior. */

// Given a function, return a new function will only run once, no matter how many times it's called
describe("once", function() {
  it("should only increment num one time", function() {
    var num = 0;
    var increment = once(function() {
      num++;
    });
    increment();
    increment();

    expect(num).toEqual(1);
  });
});

I don't quite understand what should I do here. I know I should make a function once(myFunction) {} but other than that, I am stuck. I figure out this has something to do with closures, still can't my head around it.

like image 454
Christian Sakai Avatar asked May 23 '14 18:05

Christian Sakai


2 Answers

Copied from the UnderscoreJS source:

  _.once = function(func) {
    var ran = false, memo;
    return function() {
      if (ran) return memo;
      ran = true;
      memo = func.apply(this, arguments);
      func = null;
      return memo;
    };
  };

http://underscorejs.org/docs/underscore.html

like image 75
Robert Levy Avatar answered Sep 20 '22 07:09

Robert Levy


If you prefer not to use UnderscoreJS, you can implement a simpler "once" function yourself like this:

var once = function (func) {
  var result;

  return function () {
    if (func) {
      result = func.apply(this, arguments);
      func = null;
    }

    return result;
  }
};

When you pass your function as the argument to this once function (as the parameter as 'func'), it returns a function that can only be called once.

It accomplishes this feat, in short, by creating a results variable and assigning that variable the results of calling your function with its supplied arguments--but only the first time it is run. Otherwise, when the function is invoked subsequent times, it will never enter your if statement (because the func variable was set to null in the first invocation) and the value referenced by the results variable (set during the first invocation and accessed via closure) will be returned.

like image 41
ShaneM Avatar answered Sep 21 '22 07:09

ShaneM