Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke a callback with an unknown number of parameters

Tags:

javascript

Is there a way in javascript to invoke a callback with an unknown number of parameters?

For example, if this was our invoking method:

function invokeCallback(callback, params) {
    return callback.invoke(params);
}

And if these were our example callback methods:

function action() {
    doSomeAction();
}

function greet(msg) {
    console.log(msg);
}

function nameage(name, age) {
    var msg = 'My name is ' + name + ' and my age is ' + age;
    console.log(msg);
}

And if we could then easily call them like so:

invokeCallback(action);
invokeCallback(greet, 'Hello!');
invokeCallback(nameage, 'Bob', 20);

Then it would be great.

Is something like this possible?

like image 372
Adam K Dean Avatar asked Nov 14 '13 13:11

Adam K Dean


People also ask

Can callback function have parameters?

forEach() method as an example, the callback function will always receive the current item, its index, and the array itself as arguments, in that order. You can name the parameters for them anything you want, or even omit them entirely, but the method will always pass them in as arguments.

How do you pass parameters to a call back function?

Create a Callback Function by Passing a Function as a Parameters in JavaScript. We will create a callback function by passing the function as a parameter to another function. We call the function back right after the task completes. We will make a function named sayName .

How are callbacks invoked?

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

How do you declare a callback?

A custom callback function can be created by using the callback keyword as the last parameter. It can then be invoked by calling the callback() function at the end of the function. The typeof operator is optionally used to check if the argument passed is actually a function.


2 Answers

As already mentioned in the other answers, Function.prototype.apply and Function.prototype.call are the two methods you want to look at. They differ slightly in how they operate - apply takes arguments as a single array, whilst call takes them as individual parameters.

A related concept you might wish to explore where this technique is used is currying.

With regard to your example, you should look at removing the params argument from your function definition and eliminating the opening argument which is the callback function itself:

function invokeCallback(callback) {
    var params = Array.prototype.slice.call(arguments, 1);
    return callback.apply(this, params);
}
like image 130
Luke Bennett Avatar answered Sep 28 '22 01:09

Luke Bennett


Yes, this is possible. The key function is Function#apply, which calls a function while supplying a context and parameters. The parameters are given as an array. (In this way it differs from Function#call, where the parameters are given explicitly.)

So let's look at your function signature:

function invokeCallback(callback, params) {

We could do this very simply:

function invokeCallback(callback, params) {
    return callback.apply(null, params);
}

(The first argument is the context for the function, i.e. the value of this within it. Since we don't want to specify anything particular, we use null.)

However, the way you call your function is slightly different:

invokeCallback(nameage, 'Bob', 20);

Do you see the difference? Here, the parameters are given explicitly, not as an array. We therefore need to handle it slightly differently. Within a function, the arguments object contains the arguments supplied to the function. In the above case, it would contain three: nameage, 'Bob', and 20. We want to call nameage with the parameters 'Bob' and 20.

The arguments object looks like an array, but it isn't one. We therefore have to use a slightly complex call to the Array#slice function to get the values out:

var params = Array.prototype.slice.call(arguments, 1); // get all arguments after the first one

So our function would look like this:

function invokeCallback(callback) {
    var params = Array.prototype.slice.call(arguments, 1); // get all arguments after the first one

    return callback.apply(null, params);
}
like image 36
lonesomeday Avatar answered Sep 28 '22 01:09

lonesomeday