Marcel
Marcel

Reputation: 1142

How to create instance of javascript function without using arguments

I am using a JavaScript API of some software. In software there are Solutions and they contain Worklists.

For each Solution I want to list Worklists.

solutions = obtainSolutionsformAPI();
for (i=0,i<solutions.length,i++){
    sol=solutions[i];
    sol.obtainWorklists(callbackFunction);    
}

the callbackFunction is called by software and the array of worklists is passed as the argument.

function callbackFunction(arrayOfWorkLists){
    for (j=0,j<arrayOfWorkLists.length,j++){
        wl=arrayOfWorkLists[j];
        console.log(wl);
    }
}

now in console.log I would like to also print out the i variable (the number of solution) together witch each worklist, but how do I get the i inside callback function, when I am not the one who is calling it? I suspect I need to modify the callback function each time before I pass it to sol.obtainWorklists(callbackFunction); What is the correct way of doing this?

Edit: I do not want the function defintions to be nested (one inside other), because I have multiple nestings like this one and it would be quite unreadable. So I do not want this:

sol.obtainWorklists(function callbackFunction(arrayOfWorkLists){...}); 

Upvotes: 0

Views: 70

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1075159

You can use a builder function:

sol.obtainWorklists(buildCallback(i, callbackFunction));

...where buildCallback looks like this:

function buildCallback(index, func) {
    return function() {
        var args = [index];
        args.push.apply(args, arguments);
        func.apply(this, args);
    };
}

Complete example below

Then in your callback, expect the i value as the first argument with the arguments that obtainWorklists normally provides following it.

How that works:

  • When you call buildCallback, you pass in the i value and the callback you want called.
  • buildCallback returns a new function which has that information bound to it (it's a closure over the index and func arguments in the call to buildCallback).
  • When obtainWorklists calls the function buildCallback created, we create an array with the i value (index) followed by the arguments that were received from obtainWorklists.
  • Then we call the callback, using the same this value that the function was called with, and the args array; your callback will see the entries in args as discrete arguments.

If you don't care about the this value in your callback, you can use ES5's Function#bind instead:

sol.obtainWorklists(callbackFunction.bind(null, i));

That does much the same thing, but doesn't preserve the this used to call it.


Complete example for builder function (live copy):

// obtainWorklists stand-in
function obtainWorklists(func) {
    setTimeout(function() {
        // Just call it with a random number
        func(rand(100, 200));
    }, rand(100, 500));
}

// Code to get worklists
var i;
for (i = 0; i < 10; ++i) {
    obtainWorklists(buildCallback(i, callback));
}

function buildCallback(index, func) {
    return function() {
        var args = [index];
        args.push.apply(args, arguments);
        func.apply(this, args);
    };
}


// Your callback
function callback(index, value) {
    display("Index is " + index + ", value is " + value);
}

// ========= Utility functions
function rand(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}
function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = String(msg);
    document.body.appendChild(p);
}

Complete example for Function#bind (live copy):

// obtainWorklists stand-in
function obtainWorklists(func) {
    setTimeout(function() {
        // Just call it with a random number
        func(rand(100, 200));
    }, rand(100, 500));
}

// Code to get worklists
var i;
for (i = 0; i < 10; ++i) {
    obtainWorklists(callback.bind(null, i));
}

// Your callback
function callback(index, value) {
    display("Index is " + index + ", value is " + value);
}

// ========= Utility functions
function rand(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}
function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = String(msg);
    document.body.appendChild(p);
}

Upvotes: 2

Barmar
Barmar

Reputation: 781974

You need to use a closure:

solutions = obtainSolutionsformAPI();
for (i=0,i<solutions.length,i++){
    (function(innerI) {
        sol=solutions[innerI];
        sol.obtainWorklists(function(worklists) {
            callbackFunction(worklists, innerI);
        }
    })(i);
}

function callbackFunction(arrayOfWorkLists, i){
    console.log(i);
    for (j=0,j<arrayOfWorkLists.length,j++){
        wl=arrayOfWorkLists[j];
        console.log(wl);
    }
}

Upvotes: 2

Related Questions