0

I need to define a callback, which is to be called by a external library. This callback is called with 1 parameter:

function(item) {};

In my case I need to include a second parameter which I currently solve by using the 'bind' method.

function(item) {
   var value = this.value
}.bind({'value': value});

I dont want to write this every time I need to define shuch a callback function. Instead I would like to write something like this:

function(item, value) {};

Which then would be transformed into the bind method in order to satisfy the external library.

Is that possible? Or is there some other way to do this?

Thanks

Jakob Pilsgaard
  • 120
  • 2
  • 7
  • Use a named function that you reference as the callback – adeneo Apr 12 '14 at 10:17
  • How is this callback called? What calls it? – Joseph Apr 12 '14 at 10:17
  • @adeneo: I don't understand how that would help! Can you show an example? – Jakob Pilsgaard Apr 12 '14 at 10:21
  • @JosephtheDreamer: It is called by some plugin. I don't know how it is called though! – Jakob Pilsgaard Apr 12 '14 at 10:22
  • Does `value` change all the time? or is it fixed? Is it just `value`? – Joseph Apr 12 '14 at 10:28
  • @JosephtheDreamer: the parameter 'value' is fixed through the execution of the function per call. Next time the function is called, 'value' is most likely changed. – Jakob Pilsgaard Apr 12 '14 at 10:35
  • You may wish to read this question [*Javascript curry - what are the practical applications?*](http://stackoverflow.com/questions/113780/javascript-curry-what-are-the-practical-applications) from 2008, which has a number of links you may be interested in. – RobG Apr 12 '14 at 12:25

2 Answers2

1

You want to use closures. Here's the basic pattern, though not quite as easy as what georg suggested. But performance-wise, not nearly as much of a hit (near minimal).

Define a function:

myValueFunction(value, fn){
  return fn;
}

Since it seems you're saying your plugin is providing item and you are providing the value, you will set myValueFunction(yourvalue, function(item){}) as the callback function for your plugin (with your actual value as the parameter). It'll "return" another function with your value enclosed that takes one argument (item).

So for example if you have a plugin:

var myValue= "x";
plugin.doSomething("Plugin Argument", myValueFunction(myValue, function(item){
  console.log(item, value);
}));

This is basically what georg's answer is doing (his is in a somewhat more versatile way), but his method will will be much slower performance-wise than if you define these functions directly, particularly if you start adding many arguments.

Arjun Mehta
  • 2,500
  • 1
  • 24
  • 40
  • Let me know if you need further clarification. This is a highly versatile pattern to use in situations like this! – Arjun Mehta Apr 12 '14 at 11:14
  • Thank you for the answer. This solves my problem, in this specific example, but i favor the generic behaviour answer from @georg. – Jakob Pilsgaard Apr 12 '14 at 11:41
  • Yeah, after looking it over georg's answer is somewhat versatile! – Arjun Mehta Apr 12 '14 at 11:54
  • 1
    @JakobPedersen just be sure to consider the performance hit that you'd get using that method. I updated my answer to show it in context of using a closure as a callback. – Arjun Mehta Apr 12 '14 at 12:12
  • @georg's answer (which uses Oliver Steele's *partial* function, a type of [*currying*](http://en.wikipedia.org/wiki/Currying)) is based on closures too. I don't see the need for the complexity. It does preserve the *this* though, but that can be done too using *call* if required. – RobG Apr 12 '14 at 12:26
0

You can use the function.partial implementation from here:

Function.prototype.partial = function(){
    var fn = this, args = Array.prototype.slice.call(arguments);
    return function(){
      var arg = 0;
      for ( var i = 0; i < args.length && arg < arguments.length; i++ )
        if ( args[i] === undefined )
          args[i] = arguments[arg++];
      return fn.apply(this, args);
    };
  };

Define the callback like this:

callback = function(item, value) { console.log(item + value) }.partial(undefined, "myValue")

Now when you call callback('myItem'), it correctly displays "myItem myValue"

gog
  • 10,367
  • 2
  • 24
  • 38
  • That version of *partial* may fail if one of the preinitialised arguments has the value *undefined*. Much better to get the original from [*Oliver Steele's functional.js*](http://osteele.com/sources/javascript/functional/). – RobG Apr 12 '14 at 23:05