[AC-1898] Titanium Scope Issues
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | n/a |
Status | Closed |
Resolution | Invalid |
Resolution Date | 2012-11-21T00:45:56.000+0000 |
Affected Version/s | n/a |
Fix Version/s | n/a |
Components | n/a |
Labels | n/a |
Reporter | Joel Koett |
Assignee | Mauro Parra-Miranda |
Created | 2012-11-13T21:06:51.000+0000 |
Updated | 2016-03-08T07:40:49.000+0000 |
Description
Titanium seems to be overwriting loop variables even if used within the inner function.
Example:
var window = Ti.ui.createWindow({height: 400, width: 329});
var test = ['This', 'is', 'a', 'test'];
var top = 0;
for (var x in test) {
var view = Ti.UI.createView({top: top, left: 0, width: 320, height: 10, backgroundColor: 'blue'});
var current = test[x];
top += 15;
view.addEventListener('click', function() {
alert(current);
});
window.add(view);
}
window.open();
You would expect each view to alert its corresponding word, but they all alert 'test'.
The workaround so far is to add that property to the view itself:
var window = Ti.ui.createWindow({height: 400, width: 329});
var test = ['This', 'is', 'a', 'test'];
var top = 0;
for (var x in test) {
var view = Ti.UI.createView({top: top, left: 0, width: 320, height: 10, backgroundColor: 'blue', text: test[x]});
top += 15;
view.addEventListener('click', function() {
alert(this.text);
});
window.add(view);
}
window.open();
I should also note that if I use "alert(view.text)" instead of "alert(this.text)", it still always says "test" (for the same reason, except the view variable).
"current" is being created in the global scope, hence why it gets replaced every time. A for-loop is not a function, it does not create its own scope. This is how Javascript works, it's not a Titanium issue.
As Daniel mentioned, JavaScript does not have block level scope, so view and current are actually global scope, not for-in scope. The callback function won't be executed until the current thread of execution has finished, meaning that the view and current variables will be whatever their last value was ('test' in this case since the variable is global scope). Your workaround is one way of doing it, although I would recommend another:
The forEach creates a new context for each element in test and "locks" the value of current in place. A bit of advice: always declare your variables at the top of a function/module (C style) so that you avoid logic errors like this one. For a more in-depth discussion of variable hoisting (the whole variables declared at top thing), check out http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
Invalid issue.