0

I have a JavaScript function:

function oneOf() {
    return arguments[Math.floor(Math.random()*arguments.length)];
}

It is designed to take in variable number of arguments and spit out a random one, and this works. I can't get it to take a list of object methods and execute one. How would I do this?

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293

1 Answers1

1

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`.
Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • this doesn't work for me, could it be because I am calling oneOf() from an object with arguments that are methods of the same object? –  Oct 07 '14 at 22:30
  • Nope - where `oneOf` is shouldn't matter at all - are you using `bind` or `apply` (from insights 3 / 3a)? – Sean Vieira Oct 07 '14 at 22:33