From ab81574107cd7174805ab92017402b9be3bfd921 Mon Sep 17 00:00:00 2001 From: Joseph Spens Date: Tue, 6 May 2014 14:42:43 -0400 Subject: [PATCH] Add _.before() function to negate _.after() --- test/functions.js | 22 +++++++++++++++++++++- underscore.js | 29 ++++++++++++++++------------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/test/functions.js b/test/functions.js index b4f487053..830c71b01 100644 --- a/test/functions.js +++ b/test/functions.js @@ -425,7 +425,7 @@ increment(); equal(num, 1); - equal(increment(), 1, 'stores a memo to the last value') + equal(increment(), 1, 'stores a memo to the last value'); }); test('Recursive onced function.', 1, function() { @@ -484,4 +484,24 @@ equal(testAfter(0, 1), 1, 'after(0) should fire when first invoked'); }); + test('before', function() { + var testBefore = function(beforeAmount, timesCalled) { + var beforeCalled = 0; + var before = _.before(beforeAmount, function() { beforeCalled++; }); + while (timesCalled--) before(); + return beforeCalled; + }; + + equal(testBefore(5, 5), 4, 'before(N) should not fire after being called N times'); + equal(testBefore(5, 4), 4, 'before(N) should fire before being called N times'); + equal(testBefore(0, 0), 0, 'before(0) should not fire immediately'); + equal(testBefore(0, 1), 0, 'before(0) should not fire when first invoked'); + + var context = {num: 0}; + var increment = _.before(3, function(){ return ++this.num; }); + _.times(10, increment, context); + equal(increment(), 2, 'stores a memo to the last value'); + equal(context.num, 2, 'provides context'); + }); + })(); diff --git a/underscore.js b/underscore.js index f19680671..3fae9f33c 100644 --- a/underscore.js +++ b/underscore.js @@ -776,19 +776,6 @@ }; }; - // 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; - }; - }; - // Returns the first function passed as an argument to the second, // allowing you to adjust arguments, run code before and after, and // conditionally execute the original function. @@ -825,6 +812,22 @@ }; }; + // Returns a function that will only be executed before being called N times. + _.before = function(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + else func = null; + return memo; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = _.partial(_.before, 2); + // Object Functions // ----------------