Reputation: 16281
Can someone clarify this point for me?
Two of my favourite features in JavaScript are closures and the fact that functions are first class objects.
If I want to take advantage of closure in, say, a callback function, then the function must always be an inner function. For example:
doNested();
function doNested() {
var message='Hello';
window.setTimeout(inner, 3000);
function inner() {
alert(message);
}
}
There is no way I can pass a parameter to an outer callback function. For example:
doSeparated();
function doSeparated() {
var message='Goodbye';
window.setTimeout(outer,3000);
}
function outer() {
alert(message);
}
This doesn’t work, of course.
The question is, is there any way to pass inner variables to an external function like this, short of adding them to a parameter list?
Thanks
Upvotes: 1
Views: 948
Reputation: 74204
If I want to take advantage of closure in, say, a callback function, then the function must always be an inner function.
That's correct. Every function in JavaScript only has access those variables which are either defined in its own scope or defined in a parent scope1. Therefore, your first example works while your second example doesn't.
The question is, is there any way to pass inner variables to an external function like this, short of adding them to a parameter list?
No, there's no way to do that. Well, technically you could add your inner variable to an object and then bind
that object to the external function after which you can access the inner variable from the this
context of the external function, but that is no better than passing the variable to the function directly.
doSeparated();
function doSeparated() {
var message = "Goodbye";
setTimeout(outer.bind({
message: message
}), 3000);
}
function outer() {
alert(this.message);
}
Since you are using setTimeout
, you can pass extra arguments to setTimeout
which will be given to the callback function. This gets rid of the nasty bind
:
doSeparated();
function doSeparated() {
var message = "Goodbye";
setTimeout(outer, 3000, message);
}
function outer(message) {
alert(message);
}
Note that both bind
and extra arguments of setTimeout
don't work in older versions of IE. In that case, you can use currying instead (which in my humble opinion is the best solution aside from your original nested solution):
doSeparated();
function doSeparated() {
var message = "Goodbye";
setTimeout(outer(message), 3000);
}
function outer(message) {
return function () {
alert(message);
};
}
Other than these, there's no other good solution that I can think of. The best solution is your original nested solution.
1 A function doesn't have access to any variable defined in a child scope or else you would be able to access every variable from the global scope.
Upvotes: 1