Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable Scope and Var

It all started with these simple lines of code:

a = 3;
b = 2;

function line(x) {
    var a = 5;
    var b = 4;

    return a*x+b;
}

// returns 17
b = line(a) - b;
alert(b);

// returns 36
c = line(a) + b;
alert(c);

Both alerts return 17 and 36, respectively.
The control works as expected. Until…


I make the mistake of changing
the inside of the function like so:

function line(x) {
    var a = 5; 
        b = 4;

    return a*x+b;
}

Suddenly line 13 returns 15, line 17 returns 23
and the situation continues to deteriorate as I follow var
down the rabbit hole, becoming more enmeshed as I make my descent.

I realize I could make a mental note to always use var
and rest knowing my code will always work as intended
but this has become a matter of principle now and now I need
to understand how var actually works.

Here are links to the four hells,
made by (and possibly for) me:

Riddle #1 http://jsfiddle.net/js_test/gNEmY/

Riddle #2 http://jsfiddle.net/js_test/FJVYL/

Riddle #3 http://jsfiddle.net/js_test/Vz7Sd/

Riddle #4 http://jsfiddle.net/js_test/RaA5J/

If anyone could give me insight
into what's happening under the hood
to wit, what happens during each alert() call;
I would really appreciate it.

like image 735
Wilhelm Avatar asked Mar 10 '26 21:03

Wilhelm


1 Answers

var creates a local variable, scoped to the function in which it appears. Any variable that is declared in the global scope becomes a property of the global object (in a browser, window), and any variable referenced in a function which is not declared with var in that function refers to the surrounding scope, quite possibly the global scope.

There is also a new keyword, let, which is coming in the upcoming version of ECMAScript and is already in some browsers, which creates a block-scoped variable.

So, in your first example (I am going to assume this is running in a browser), you create window.a and window.b which are bound to 3 and 2, respectively. Function line declares local variables a and b. When window.a is passed to line, the parameter x is bound to the value 3 (the value of window.a). Local variables a and b are 5 and 4, respectively. These have nothing to do with window.a and window.b. The calculation a*x+b is, thus, 5*3+4, or 19.

The code b = line(a) - b passes window.a to line, calculates the value 19, subtracts the current value of window.b from it (2), resulting in 17, which is then assigned to window.b. The value of 36 comes from line(3) (which is still 19) plus 17 (the new value of window.b).

When you removed the var from the assignment to b in function line, you changed it so that b is no longer a local variable. In that case, all references to b in the function refer to the global value window.b.

In the case of your Riddle #2, where you got 23, after the first call window.b is equal to 15. When line(a) is called a second time, window.b is set back to 4, the a*x+b calculation still gets 19, and then window.b (4) is added again, making 23.

It is important to note that the var keyword declares a variable that is function-scoped, not block-scoped as you might expect from other C-derived languages. For example, in this function:

function scope(array) {
    var a = 7;

    for (var b = 0; b < array.length; ++b) {
        var c = array[b];
    }

    alert(a + b + c);
}

All the variables have scope which extends over the entire function. In particular, the scope of c is not limited to the for loop.

A variable that is not declared in a particular scope doesn't necessarily reference a global variable, however. If it is nested inside another function scope, it will refer to that nested scope. Consider the following example:

var b = 7;

function outer() {
    var b = 42;

    function inner() {
        return b; // refers to b in outer, not global
    }

    return inner();
}

alert(outer()); // 42, not 7
like image 90
David Conrad Avatar answered Mar 12 '26 09:03

David Conrad