The name of the concept that is causing you confusion is closure (
In JavaScript, only functions define a new lexical context (other languages have different rules - some even support the concept of closure):
var a = 10; // Mesmo "a" para script1.js, script2.js, etc (efetivamente, uma global)
function f() {
var b = 20; // Um "b" diferente para cada invocação de f
if ( x ) {
var c = 30; // Mesmo "c" dentro e fora do if (i.e. o contexto é "f", não o bloco if)
And each new context created within an existing context has access to all the variables defined in the "outer" :
>
function x(a1) { // "x" tem acesso a "a"
var a2;
function y(b1) { // "y" tem acesso a "a" e "b"
var b2;
function z(c1) { // "z" tem acesso a "a", "b", e "c"
var c2;
It is important to note that when the internal function will run, nor what value the external variables had at the time the object function was created (by contrast with the definition of the function, which is at compile / interpretation time). What matters is that both share the same variable, and written on one side will reflect on each other's readings and vice versa.
In your case, you are creating a new (anonymous) function within the lexical context of the external code (another function? body of the script?), and it shares the variable i
not value of i
). At the moment this function is executed, the for
loop has already changed its value several times, taking it to its maximum value ( 50
) and this is what the internal function will access. If the external code modified or reused i
for other purposes, this would also be reflected in the internal function (and likewise, if one of the function objects changed that i
it would interfere with the others as well.)
There are several ways to modify the code to achieve the desired behavior (ie a i
different for each object-function) - as already pointed out by @Sergio - but my favorite is that which makes the nature of < in> closure more explicit (even if it seems visually "strange" to anyone unfamiliar with the concept):
for (var i = 0; i < 50; i++) {
(function(i) {
setTimeout(function() {
textArea.value += 'Mensagem ' + i + '\n';
textArea.scrollTop = textArea.scrollHeight;
}, 100 * i);
})(i);
}
Note that the i
argument of the anonymous function is not the same as i
passed as parameter to it - since they are in different lexical contexts. It should also be noted that the variable textArea
is still coming from the external context, and depending on the case it may be interesting to include it in the closure as well:
(function(i, textArea) { ... })(i, textArea);
This ensures that - even if this variable has its value changed (i.e., it points to a different element) - the inner function still has access to the value it had at the time the loop was executed.