diff --git a/test/functions.js b/test/functions.js index b37fc8976..83c69d730 100644 --- a/test/functions.js +++ b/test/functions.js @@ -107,14 +107,13 @@ $(document).ready(function() { setTimeout(debouncedIncr, 150); _.delay(function(){ ok(counter == 1, "incr was debounced"); start(); }, 220); }); - + test("functions: once", function() { - var addBang = function(str) { return str + "!"; }; - hi = "Hi"; - hi2 = _.once(addBang, hi); - hi3 = _.once(addBang, hi); - equals(hi2, "Hi!"); - equals(hi3, undefined); + var num = 0; + var increment = _.once(function(){ num++; }); + increment(); + increment(); + equals(num, 1); }); test("functions: wrap", function() { diff --git a/underscore.js b/underscore.js index cfe7cea44..e214dbd51 100644 --- a/underscore.js +++ b/underscore.js @@ -474,17 +474,17 @@ _.debounce = function(func, wait) { return limit(func, wait, true); }; - - // Runs a function only if it's never been run before. + + // 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) { - if (_.indexOf(onceRunFunctions, func)) { - onceRunFunctions.push(func); - return func.apply(func, slice.call(arguments, 1)); - } - } - - // Internal record of functions that have been run via `_.once`. - var onceRunFunctions = []; + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; // Returns the first function passed as an argument to the second, // allowing you to adjust arguments, run code before and after, and