2009-03-05 19:56:01 +00:00
|
|
|
/** section: Language
|
|
|
|
* class Function
|
2009-06-11 20:48:38 +00:00
|
|
|
*
|
2009-03-20 10:46:53 +00:00
|
|
|
* Extensions to the built-in `Function` object.
|
2008-12-14 04:36:59 +00:00
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
Object.extend(Function.prototype, (function() {
|
|
|
|
var slice = Array.prototype.slice;
|
2009-06-11 20:48:38 +00:00
|
|
|
|
2008-12-11 10:49:41 +00:00
|
|
|
function update(array, args) {
|
|
|
|
var arrayLength = array.length, length = args.length;
|
|
|
|
while (length--) array[arrayLength + length] = args[length];
|
|
|
|
return array;
|
|
|
|
}
|
2009-06-11 20:48:38 +00:00
|
|
|
|
2008-12-11 10:49:41 +00:00
|
|
|
function merge(array, args) {
|
|
|
|
array = slice.call(array, 0);
|
|
|
|
return update(array, args);
|
|
|
|
}
|
2009-06-11 20:48:38 +00:00
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/**
|
|
|
|
* Function#argumentNames() -> Array
|
|
|
|
*
|
|
|
|
* Reads the argument names as stated in the function definition and returns
|
|
|
|
* the values as an array of strings (or an empty array if the function is
|
|
|
|
* defined without parameters).
|
2009-09-10 09:31:56 +00:00
|
|
|
*
|
|
|
|
* ### Examples
|
|
|
|
*
|
|
|
|
* function fn(foo, bar) {
|
|
|
|
* return foo + bar;
|
|
|
|
* }
|
|
|
|
* fn.argumentNames();
|
|
|
|
* //-> ['foo', 'bar']
|
|
|
|
*
|
|
|
|
* Prototype.emptyFunction.argumentNames();
|
|
|
|
* //-> []
|
2008-12-14 04:36:59 +00:00
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
function argumentNames() {
|
2008-10-26 20:33:10 +00:00
|
|
|
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
|
|
|
|
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
|
2008-12-11 10:42:15 +00:00
|
|
|
.replace(/\s+/g, '').split(',');
|
|
|
|
return names.length == 1 && !names[0] ? [] : names;
|
2008-12-11 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/**
|
|
|
|
* Function#bind(object[, args...]) -> Function
|
|
|
|
* - object (Object): The object to bind to.
|
|
|
|
*
|
|
|
|
* Wraps the function in another, locking its execution scope to an object
|
|
|
|
* specified by `object`.
|
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
function bind(context) {
|
2008-12-11 10:42:15 +00:00
|
|
|
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
|
2008-12-11 10:49:41 +00:00
|
|
|
var __method = this, args = slice.call(arguments, 1);
|
2008-12-11 10:42:15 +00:00
|
|
|
return function() {
|
2008-12-11 10:49:41 +00:00
|
|
|
var a = merge(args, arguments);
|
|
|
|
return __method.apply(context, a);
|
2008-12-11 10:42:15 +00:00
|
|
|
}
|
2008-12-11 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/** related to: Function#bind
|
|
|
|
* Function#bindAsEventListener(object[, args...]) -> Function
|
|
|
|
* - object (Object): The object to bind to.
|
|
|
|
*
|
|
|
|
* An event-specific variant of [[Function#bind]] which ensures the function
|
|
|
|
* will recieve the current event object as the first argument when
|
|
|
|
* executing.
|
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
function bindAsEventListener(context) {
|
|
|
|
var __method = this, args = slice.call(arguments, 1);
|
2008-12-11 10:42:15 +00:00
|
|
|
return function(event) {
|
2008-12-11 10:49:41 +00:00
|
|
|
var a = update([event || window.event], args);
|
|
|
|
return __method.apply(context, a);
|
2008-12-11 10:42:15 +00:00
|
|
|
}
|
2008-12-11 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/**
|
|
|
|
* Function#curry(args...) -> Function
|
|
|
|
* Partially applies the function, returning a function with one or more
|
2009-06-11 20:48:38 +00:00
|
|
|
* arguments already "filled in."
|
2008-12-14 04:36:59 +00:00
|
|
|
*
|
|
|
|
* Function#curry works just like [[Function#bind]] without the initial
|
|
|
|
* scope argument. Use the latter if you need to partially apply a function
|
|
|
|
* _and_ modify its execution scope at the same time.
|
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
function curry() {
|
2008-12-11 10:42:15 +00:00
|
|
|
if (!arguments.length) return this;
|
2008-12-11 10:49:41 +00:00
|
|
|
var __method = this, args = slice.call(arguments, 0);
|
2008-12-11 10:42:15 +00:00
|
|
|
return function() {
|
2008-12-11 10:49:41 +00:00
|
|
|
var a = merge(args, arguments);
|
|
|
|
return __method.apply(this, a);
|
2008-12-11 10:42:15 +00:00
|
|
|
}
|
2008-12-11 10:49:41 +00:00
|
|
|
}
|
2008-12-11 10:42:15 +00:00
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/**
|
|
|
|
* Function#delay(seconds[, args...]) -> Number
|
|
|
|
* - seconds (Number): How long to wait before calling the function.
|
|
|
|
*
|
|
|
|
* Schedules the function to run after the specified amount of time, passing
|
|
|
|
* any arguments given.
|
|
|
|
*
|
|
|
|
* Behaves much like `window.setTimeout`. Returns an integer ID that can be
|
|
|
|
* used to clear the timeout with `window.clearTimeout` before it runs.
|
|
|
|
*
|
|
|
|
* To schedule a function to run as soon as the interpreter is idle, use
|
|
|
|
* [[Function#defer]].
|
|
|
|
**/
|
2009-06-11 20:48:38 +00:00
|
|
|
function delay(timeout) {
|
2008-12-11 10:49:41 +00:00
|
|
|
var __method = this, args = slice.call(arguments, 1);
|
|
|
|
timeout = timeout * 1000
|
2008-12-11 10:42:15 +00:00
|
|
|
return window.setTimeout(function() {
|
|
|
|
return __method.apply(__method, args);
|
|
|
|
}, timeout);
|
2008-12-11 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/**
|
|
|
|
* Function#defer(args...) -> Number
|
|
|
|
* Schedules the function to run as soon as the interpreter is idle.
|
|
|
|
*
|
2009-06-11 20:48:38 +00:00
|
|
|
* A "deferred" function will not run immediately; rather, it will run as soon
|
|
|
|
* as the interpreter's call stack is empty.
|
2008-12-14 04:36:59 +00:00
|
|
|
*
|
|
|
|
* Behaves much like `window.setTimeout` with a delay set to `0`. Returns an
|
|
|
|
* ID that can be used to clear the timeout with `window.clearTimeout` before
|
|
|
|
* it runs.
|
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
function defer() {
|
|
|
|
var args = update([0.01], arguments);
|
2008-12-11 10:42:15 +00:00
|
|
|
return this.delay.apply(this, args);
|
2008-12-11 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/**
|
|
|
|
* Function#wrap(wrapperFunction) -> Function
|
|
|
|
* - wrapperFunction (Function): The function to act as a wrapper.
|
|
|
|
*
|
2009-06-11 20:48:38 +00:00
|
|
|
* Returns a function "wrapped" around the original function.
|
2008-12-14 04:36:59 +00:00
|
|
|
*
|
|
|
|
* `Function#wrap` distills the essence of aspect-oriented programming into
|
|
|
|
* a single method, letting you easily build on existing functions by
|
|
|
|
* specifying before and after behavior, transforming the return value, or
|
|
|
|
* even preventing the original function from being called.
|
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
function wrap(wrapper) {
|
2008-12-11 10:42:15 +00:00
|
|
|
var __method = this;
|
|
|
|
return function() {
|
2008-12-11 10:49:41 +00:00
|
|
|
var a = update([__method.bind(this)], arguments);
|
|
|
|
return wrapper.apply(this, a);
|
2008-12-11 10:42:15 +00:00
|
|
|
}
|
2008-12-11 10:49:41 +00:00
|
|
|
}
|
|
|
|
|
2008-12-14 04:36:59 +00:00
|
|
|
/**
|
|
|
|
* Function#methodize() -> Function
|
|
|
|
* Wraps the function inside another function that, at call time, pushes
|
|
|
|
* `this` to the original function as the first argument.
|
|
|
|
*
|
|
|
|
* Used to define both a generic method and an instance method.
|
|
|
|
**/
|
2008-12-11 10:49:41 +00:00
|
|
|
function methodize() {
|
2008-12-11 10:42:15 +00:00
|
|
|
if (this._methodized) return this._methodized;
|
|
|
|
var __method = this;
|
|
|
|
return this._methodized = function() {
|
2008-12-11 10:49:41 +00:00
|
|
|
var a = update([this], arguments);
|
|
|
|
return __method.apply(null, a);
|
2008-12-11 10:42:15 +00:00
|
|
|
};
|
|
|
|
}
|
2009-06-11 20:48:38 +00:00
|
|
|
|
2008-12-11 10:49:41 +00:00
|
|
|
return {
|
|
|
|
argumentNames: argumentNames,
|
|
|
|
bind: bind,
|
|
|
|
bindAsEventListener: bindAsEventListener,
|
|
|
|
curry: curry,
|
|
|
|
delay: delay,
|
|
|
|
defer: defer,
|
|
|
|
wrap: wrap,
|
|
|
|
methodize: methodize
|
|
|
|
}
|
|
|
|
})());
|
|
|
|
|