I think you hit a very common problem of imperative languages that have first-class functions as functional languages do but lack referential transparency. The result are (as a functional programmer would call it) broken closures. I hit this problem in Python some years ago, too and is was quite frustrating. Some weeks ago, this blog post hit my Google+ stream discussing the same issue.
As a sample, take the following code (please excuse I'm not demonstrating it using OpenLayers since I know nothing about OpenLayers and nearly nothing about JavaScript (so excuse the possible use of JS anti-patterns))
function foo_broken() {
var xs = [];
for (var i = 0; i < 10; i++) {
var bar = function() { return i; }
xs.push(bar);
}
return xs;
}
function foo_working() {
var xs = [];
for (var i = 0; i < 10; i++) {
var bar = function(t) { return function() { return t; } };
xs.push(bar(i));
}
return xs;
}
I think most users would expect foo_broken()
and foo_working()
to do exact the same thing, but no, not in JavaScript. The test code below alerts 10,10,10,10,10,10,10,10,10,10
when evaluating the list returned by foo_broken()
and 0,1,2,3,4,5,6,7,8,9
for foo_working()
.
The problem is that the closure for the anonymous function assigned to bar
does not contain the current value of i
but a reference to the variable i
. That's the reason it's always the last value assigned to that variable. It's IMHO broken but it's like JavaScript, Python 2 and some other languages do it :-(.
The pattern to fight this issue I always use is to define another function which takes as many arguments as the values I'd like to force. In the demo above it's only one parameter (t
) because I simply want the value of i
. So to force the evaluation of variable i
I pass it as a parameter to the anonymous function inside the loop and so the JavaScript interpreter is forced to evaluate it inside the loop.
function alert_values(fun) {
var bars = fun();
value_strs = "";
for (var i = 0; i < 10; i++) {
value_strs += "" + bars[i]() + ",";
}
alert(value_strs);
}
alert_values(foo_broken);
alert_values(foo_working);
Best Answer
Yeah it was stupid question. But if someone interest for filter features you can use Openlayers.filter something like this: