Insight #1
Function.prototype.apply
allows you to "splat" an array into the arguments list:
function sayAll() {
console.log(arguments);
}
sayAll(1, 2, 3, 4);
// [1, 2, 3, 4]
sayAll.apply(null, ["a", "b", "c"])
// ["a", "b", "c"]
Insight #2
Functions can be invoked with parenthesis (see above).
Combining these two insights, we get the following:
function oneOf() {
var f = arguments[Math.floor(Math.random()*arguments.length)];
return f(); // Via insight #2
}
// Via insight #1
oneOf.apply(null, [someFunction, anotherFunction]);
If these functions are "methods" on an object and need to retain their this
context, then we'll need a third insight.
Insight #3
Function.prototype.bind
allows creating a function with a fixed this
context:
function sayWhatThisIs() {
console.log("This is", this);
}
var coolObject = {
cool: true,
sayWhat: sayWhatThisIs
};
coolObject.sayWhat();
// This is {cool: true, ...}
oneOf.apply(null, [coolObject.sayWhat.bind(coolObject),
sayWhatThisIs.bind(coolObject)]);
// Two variations of binding `sayWhatThisIs` to `coolObject`
Insight #3a
We could also pass on the this
context of oneOf
to Function.prototype.apply
:
function oneOf() {
var f = arguments[Math.floor(Math.random()*arguments.length)];
return f.apply(this);
}
onOf.apply(coolObject, [coolObject.sayWhat, sayWhatThisIs]);
// Now applying insight #3a to set `onOf`'s `this` context to `coolObject`.