Javascript: Passing custom arguments to a callback function
I have this callback function setup:
var contextMenu = [];
var context = [ { "name": "name1", "url": "url1" }, {"name": name2", "url: "url2" } ];
for(var i=0; i < context.length; i++) {
var c = context[i];
var arr = {};
arr[c.name] = function() { callback(c.url); }
contextMenu.push( arr );
}
function callback(url) {
alert(url);
}
The problem is that the url value passed to the callback is always the last value in the context variable - in this case "url2". I am expecting to pass specific values to each "instance" of the callback, but as the callback seems to be remember the sa开发者_开发百科me value, the last time it was referred.
I am kind of stuck. Any help would be appreciated.
PS: I am using jQuery ContextMenu which, to my understanding, does not support sending custom data to its callback functions. It is in this context that I have this problem. Any suggestions to overcome in this environment is also helpful!
Use an additional closure.
arr[c.name] = (function(url) {
return function() { callback(url); }
})(c.url);
See Creating closures in loops: A common mistake and most other questions on this topic, and now your question is also added to this pool.
You are creating a series of closure functions inside the for loop
arr[c.name] = function() { callback(c.url); }
and they all share the same scope, and hence the same c
object which will point to the last element in your array after the loop finishes.
To overcome this issue, try doing this:
arr[c.name] = function(url) {
return function() { callback(url); };
}(c.url);
Read more about closures here: http://jibbering.com/faq/notes/closures/
General solution
Callback creator helper
I created a general callback creator along the Creating closures in loops: A common mistake that Anurag pointed out in his answer.
Parameters of the callback creator
- The function's first parameter is the callback.
- Every other parameter will be passed to this callback as parameters.
Parameters of the passed callback
- First part of the parameters come from the arguments you passed to the callback creator helper (after the first parameter as I described previously).
- Second part comes from the arguments that will be directly passed to the callback by its caller.
Source code
//Creates an anonymus function that will call the first parameter of
//this callbackCreator function (the passed callback)
//whose arguments will be this callbackCreator function's remaining parameters
//followed by the arguments passed to the anonymus function
//(the returned callback).
function callbackCreator() {
var functionToCall = arguments[0];
var argumentsOfFunctionToCall = Array.prototype.slice.apply(arguments, [1]);
return function () {
var argumentsOfCallback = Array.prototype.slice.apply(arguments, [0]);
functionToCall.apply(this, argumentsOfFunctionToCall.concat(argumentsOfCallback));
}
}
Example usage
Here is a custom AJAX configuration object whose success callback uses my callback creator helper. With the response text the callback updates the first cell of a row in a DataTables table based on which row the action happened, and prints a message.
{
url: 'example.com/data/' + elementId + '/generate-id',
method: 'POST',
successHandler: callbackCreator(function (row, message, response) {//Callback parameters: Values we want to pass followed with the arguments passed through successHandler.
table.cell(row, 0).data(JSON.parse(response).text);
console.log(message);
},
$(this).parents('tr'),//Row value we want to pass for the callback.
actionName + ' was successful'//Message value we want to pass for the callback.
)
}
Or in your case:
arr[c.name] = callbackCreator(function(url) {
callback(url);
},
c.url
);
精彩评论