166 lines
5.3 KiB
JavaScript
166 lines
5.3 KiB
JavaScript
/** section: Language
|
||
* class Function
|
||
**/
|
||
Object.extend(Function.prototype, (function() {
|
||
var slice = Array.prototype.slice;
|
||
|
||
function update(array, args) {
|
||
var arrayLength = array.length, length = args.length;
|
||
while (length--) array[arrayLength + length] = args[length];
|
||
return array;
|
||
}
|
||
|
||
function merge(array, args) {
|
||
array = slice.call(array, 0);
|
||
return update(array, args);
|
||
}
|
||
|
||
/**
|
||
* 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).
|
||
**/
|
||
function argumentNames() {
|
||
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
|
||
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
|
||
.replace(/\s+/g, '').split(',');
|
||
return names.length == 1 && !names[0] ? [] : names;
|
||
}
|
||
|
||
/**
|
||
* 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`.
|
||
**/
|
||
function bind(context) {
|
||
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
|
||
var __method = this, args = slice.call(arguments, 1);
|
||
return function() {
|
||
var a = merge(args, arguments);
|
||
return __method.apply(context, a);
|
||
}
|
||
}
|
||
|
||
/** 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.
|
||
**/
|
||
function bindAsEventListener(context) {
|
||
var __method = this, args = slice.call(arguments, 1);
|
||
return function(event) {
|
||
var a = update([event || window.event], args);
|
||
return __method.apply(context, a);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Function#curry(args...) -> Function
|
||
* Partially applies the function, returning a function with one or more
|
||
* arguments already “filled in.”
|
||
*
|
||
* 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.
|
||
**/
|
||
function curry() {
|
||
if (!arguments.length) return this;
|
||
var __method = this, args = slice.call(arguments, 0);
|
||
return function() {
|
||
var a = merge(args, arguments);
|
||
return __method.apply(this, a);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 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]].
|
||
**/
|
||
function delay(timeout) {
|
||
var __method = this, args = slice.call(arguments, 1);
|
||
timeout = timeout * 1000
|
||
return window.setTimeout(function() {
|
||
return __method.apply(__method, args);
|
||
}, timeout);
|
||
}
|
||
|
||
/**
|
||
* Function#defer(args...) -> Number
|
||
* Schedules the function to run as soon as the interpreter is idle.
|
||
*
|
||
* A “deferred” function will not run immediately; rather, it will run as soon
|
||
* as the interpreter’s call stack is empty.
|
||
*
|
||
* 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.
|
||
**/
|
||
function defer() {
|
||
var args = update([0.01], arguments);
|
||
return this.delay.apply(this, args);
|
||
}
|
||
|
||
/**
|
||
* Function#wrap(wrapperFunction) -> Function
|
||
* - wrapperFunction (Function): The function to act as a wrapper.
|
||
*
|
||
* Returns a function “wrapped” around the original function.
|
||
*
|
||
* `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.
|
||
**/
|
||
function wrap(wrapper) {
|
||
var __method = this;
|
||
return function() {
|
||
var a = update([__method.bind(this)], arguments);
|
||
return wrapper.apply(this, a);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 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.
|
||
**/
|
||
function methodize() {
|
||
if (this._methodized) return this._methodized;
|
||
var __method = this;
|
||
return this._methodized = function() {
|
||
var a = update([this], arguments);
|
||
return __method.apply(null, a);
|
||
};
|
||
}
|
||
|
||
return {
|
||
argumentNames: argumentNames,
|
||
bind: bind,
|
||
bindAsEventListener: bindAsEventListener,
|
||
curry: curry,
|
||
delay: delay,
|
||
defer: defer,
|
||
wrap: wrap,
|
||
methodize: methodize
|
||
}
|
||
})());
|
||
|