These methods can be chained
var functionMethods = module.exports = {
    makeFunction: makeFunction,
    partial: partial,
    partialRight: partialRight,
    memoize: memoize,
    delay: delay,
    defer: defer,
    delayed: delayed,
    deferred: deferred,
    deferTicks: deferTicks,
    delayMethod: delayMethod,
    deferMethod: deferMethod,
    debounce: debounce,
    throttle: throttle,
    once: once,
    waitFor: waitFor,
    not: not
};
var slice = Array.prototype.slice;
| Option name | Type | Description | 
|---|---|---|
| name | String | new function name | 
| arg1, | String | arg2, ... the names of function parameters | 
| funcBody | String | function body | 
| return | Function | 
Similarly to Function constructor creates a function from code.
Unlike Function constructor, the first argument is a function name
function makeFunction(arg1, arg2, funcBody) {
    var name = this
        , count = arguments.length - 1
        , funcBody = arguments[count]
        , func
        , code = '';
    for (var i = 0; i < count; i++)
        code += ', ' + arguments[i];
    code = ['func = function ', name, '(', code.slice(2), ') {\n'
                , funcBody, '\n}'].join('');
    eval(code);
    return func;
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | Function to be applied | 
| arguments | List | Arguments after self will be prepended to the original function call when the partial function is called. | 
| return | Function | 
Creates a function as a result of partial function application with the passed parameters.
function partial() { // , ... arguments
    var func = this;
    var args = slice.call(arguments);
    return function() {
        return func.apply(this, args.concat(slice.call(arguments)));
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | Function to be applied | 
| arguments | List | Arguments after self will be appended on the right to the original function call when the partial function is called. | 
| return | Function | 
Creates a function as a result of partial function application with the passed parameters, but parameters are appended on the right.
function partialRight() { // , ... arguments
    var func = this;
    var args = slice.call(arguments);
    return function() {
        return func.apply(this, slice.call(arguments).concat(args));
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function to be memoized | 
| hashFunc | Function | optional hash function that is passed all function arguments and should return cache key. | 
| limit | Integer | optional maximum number of results to be stored in the cache. 1000 by default. | 
| return | Function | memoized function | 
Creates a memoized version of the function using supplied hash function as key. If the hash is not supplied, uses its first parameter as the hash.
function memoize(hashFunc, limit) {
    var func = this;
    var cache = {}, keysList = [];
    limit = limit || 1000;
    return function() {
        var key = hashFunc ? hashFunc.apply(this, arguments) : arguments[0];
        if (cache.hasOwnProperty(key))
            return cache[key];
        var result = cache[key] = func.apply(this, arguments);
        keysList.push(key);
        if (keysList.length > limit)
            delete cache[keysList.shift()];
        return result;
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function that execution has to be delayed | 
| wait | Number | approximate dalay time in milliseconds | 
| arguments | List | optional arguments that will be passed to the function | 
Delays function execution by a given time in milliseconds.
The context in function when it is executed is set to null.
function delay(wait) { // , arguments
    var args = slice.call(arguments, 1);
    return _delay(this, wait, args);
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function that execution has to be delayed | 
| arguments | List | optional arguments that will be passed to the function | 
Defers function execution (executes as soon as execution loop becomes free)
The context in function when it is executed is set to null.
function defer() { // , arguments
    return _delay(this, 1, arguments);
}
function _delay(func, wait, args, context) {
    return setTimeout(func.apply.bind(func, context || null, args), wait);
}
Same as _.defer, takes first argument as the function to be deferred
var deferFunc = makeProtoFunction(defer);
| Option name | Type | Description | 
|---|---|---|
| self | Function | function that execution has to be delayed | 
| ticks | Integer | number of times to defer execution | 
| arguments | List | optional arguments that will be passed to the function | 
Defers function execution for times ticks (executes after execution loop becomes free times times)
The context in function when it is executed is set to null.
function deferTicks(ticks) { // , arguments
    if (ticks < 2) return defer.apply(this, arguments);
    var args = repeat.call(deferFunc, ticks - 1);
    args = args.concat(this, slice.call(arguments, 1)); 
    return deferFunc.apply(null, args);
}
| Option name | Type | Description | 
|---|---|---|
| self | Object | object to delay method call of | 
| funcOrMethodName | Function, String | function or name of method | 
| wait | Number | approximate dalay time in milliseconds | 
| arguments | List | arguments to pass to method | 
Works like .delay but allows to defer method call of self which will be the first .delayMethod parameter
function delayMethod(funcOrMethodName, wait) { // , ... arguments
    var args = slice.call(arguments, 2);
    return _delayMethod(this, funcOrMethodName, wait, args);
}
| Option name | Type | Description | 
|---|---|---|
| self | Object | object to defer method call of | 
| funcOrMethodName | Function, String | function or name of method | 
| arguments | List | arguments to pass to method | 
Works like .defer but allows to defer method call of self which will be the first .deferMethod parameter
function deferMethod(funcOrMethodName) { // , ... arguments
    var args = slice.call(arguments, 1);
    return _delayMethod(this, funcOrMethodName, 1, args);
}
function _delayMethod(object, funcOrMethodName, wait, args) {
    return setTimeout(function() {
        var func = typeof funcOrMethodName == 'string'
                    ? object[funcOrMethodName]
                    : funcOrMethodName;
        func.apply(object, args);
    }, wait);
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function which execution has to be deferred | 
| wait | Number | approximate dalay time in milliseconds | 
| arguments | List | optional arguments that will be passed to the function | 
| return | Function | 
Returns function that will execute the original function wait ms after it has been called
The context in function when it is executed is set to null.
Arguments passed to the function are appended to the arguments passed to delayed.
function delayed(wait) { //, ... arguments
    var func = this
        , args = slice.call(arguments, 1);
    return function() { // ... arguments
        var passArgs = args.concat(slice.call(arguments));
        return _delay(func, wait, passArgs, this);
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function which execution has to be deferred | 
| arguments | List | optional arguments that will be passed to the function | 
| return | Function | 
Returns function that will execute the original function on the next tick once it has been called
The context in function when it is executed is set to null.
Arguments passed to the function are appended to the arguments passed to deferred.
function deferred() { //, ... arguments
    var func = this
        , args = slice.call(arguments);
    return function() { // ... arguments
        var passArgs = args.concat(slice.call(arguments));
        return _delay(func, 1, passArgs, this);
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function that execution has to be delayed | 
| wait | Number | approximate dalay time in milliseconds | 
| immediate | Boolean | true to invoke funciton immediately and then ignore following calls for wait milliseconds | 
| return | Function | 
Creates a function that will call original function once it has not been called for a specified time
function debounce(wait, immediate) {
    var func = this; // first parameter of _.debounce
    var timeout, args, context, timestamp, result;
    return function() {
        context = this; // store original context
        args = arguments;
        timestamp = Date.now();
        var callNow = immediate && ! timeout;
        if (! timeout)
            timeout = setTimeout(later, wait);
        if (callNow)
            result = func.apply(context, args);
        return result;
        function later() {
            var last = Date.now() - timestamp;
            if (last < wait)
                timeout = setTimeout(later, wait - last);
            else {
                timeout = null;
                if (! immediate)
                    result = func.apply(context, args);
            }
        }
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function that execution has to be delayed | 
| wait | Number | approximate delay time in milliseconds | 
| options | Object | 
 | 
| return | Function | 
Returns a function, that, when invoked, will only be triggered at most once during a given window of time.
function throttle(wait, options) {
    var func = this; // first parameter of _.throttle
    var context, args, result;
    var timeout = null;
    var previous = 0;
    options || (options = {});
    return function() {
        var now = Date.now();
        if (!previous && options.leading === false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0) {
            clearTimeout(timeout);
            timeout = null;
            previous = now;
            result = func.apply(context, args);
        } else if (!timeout && options.trailing !== false)
            timeout = setTimeout(later, remaining);
        return result;
    };
    function later() {
        previous = options.leading === false ? 0 : Date.now();
        timeout = null;
        result = func.apply(context, args);
    }
}
Call passed function only once
function once() {
    var func = this
        , ran = false
        , memo;
    return function() {
        if (ran) return memo;
        ran = true;
        memo = func.apply(this, arguments);
        func = null;
        return memo;
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function: if it returns true the callback is executed | 
| callback | Function | runs when the condition is true | 
| maxTimeout | Number | timeout before giving up (time in milliseconds) | 
| timedOutFunc | Function | a function called if timeout is reached | 
| checkInterval | Number | time interval when you run the condition function (time in milliseconds), default 50 ms | 
Execute a function when the condition function returns a truthy value
it runs the condition function every checkInterval milliseconds (default 50)
function waitFor(callback, maxTimeout, timedOutFunc, checkInterval){
    var start = Date.now();
    var condition = this;
    checkInterval = checkInterval || 50;
    var interval = setInterval(testCondition, checkInterval);
    function testCondition() {
        if (condition()) callback();
        else if (Date.now() - start >= maxTimeout)
            timedOutFunc && timedOutFunc();
        else return;
        clearInterval(interval);
    };
}
| Option name | Type | Description | 
|---|---|---|
| self | Function | function to negate | 
| return | Function | 
returns the function that negates (! operator) the result of the original function
function not() {
    var func = this;
    return function() {
        return !func.apply(this, arguments);
    };
}