2

Possible Duplicate:
JavaScript Variable Scope

I am (obviously) pretty new to Javascript, and I've seen several different points on other threads about the usage of Global and Local variables, but I'm trying to lock down some basic points on the subject in one place.

What is the difference between the following, declared outside (or used inside) of a function?

var thing = 1;

thing = 1;

I understand that using var declares the variable in it's current scope. So leaving out var makes it global. What are some pitfalls that can show up? Could someone give a simple example of where variables might step on each other in this case?

Thanks in advance.

Community
  • 1
  • 1
Benny
  • 242
  • 1
  • 5
  • 17
  • 3
    Please go through this link. It will surely help:- http://stackoverflow.com/questions/500431/javascript-variable-scope – Rahul Tripathi Oct 09 '12 at 17:47
  • Try writing a bunch of code without ever using `var`. You'll discover the pitfalls soon enough. – I Hate Lazy Oct 09 '12 at 17:50
  • 1
    @RahulTripathi thanks for the link, that one is great. I had searched several other threads like http://stackoverflow.com/questions/6628209/global-local-variables-in-javascript and http://stackoverflow.com/questions/1276095/javascript-local-vs-global but a list like that is great to have – Benny Oct 09 '12 at 18:40

3 Answers3

2
  1. If you are in the global scope already, the difference is so small that you don't have to worry about it

  2. imagine that you had two for loops, and you wanted to do something with them.

.

for (i = 0; i < elements.length; i++) {
    element = elements[i];
    for (i = 0; i < items.length) {
        item = items[i];
        element.add(item);
    }
}

This piece of pseudo-code would work fine in many different languages. The program would see an inner-loop and an outer-loop, and could tell that i wasn't referring to the same thing.

In JavaScript, they're the same i.
That's because other languages have block-scope -- any time you enter new curly braces, the program treats variables like they're new.

In JavaScript there is only function scope, meaning that inside of functions variables are treated as new, but inside of control statements (if, for, switch), they're the same variable with the same value.
So the outer loop sets i to 0, and then goes into the inner loop.
The inner loop goes through all of its list of items, and builds i up as it goes...
Then it goes back to the outer loop, and i still equals items.length - 1...
If that's less than elements.length then it adds one to i, which is now higher than items length, so nothing happens in the inner loop, anymore...
...if items.length is greater than elements.length instead, then the outer loop just ends after one time through.

Now, I'm sure that you can start to think about times where you might want to use x or name or value or el or sum or i or default or src or url or img or script, etc several times in your whole program (tens of thousands of lines, even), and you can start to think about situations like that loop up above, where things could go wrong if you tried calling two different things by the same name.

This is the same problem as var-fallthrough

If you have one function which uses a variable called x and another function which uses another variable called x, that's great... ...unless you forget to declare the variable.

// no problems!
function func1 () { var x = 0; }
function func2 () { var x = "Bob"; }

// big problems!
function func1 () { x = 0; }
function func2 () { x = "Bob"; }

func1 set window.x = 0; func2 set window.x = "Bob";

...if window.x was supposed to equal 42, for some other program to work right, now you have the potential to have 3 broken apps, just because of a few missing vars.

It doesn't instantly set the global variable, though. What it actually does is goes through the function chain. If you create a function inside of another function, then an undeclared var will look to its parent's vars, and then its grandparent's vars and then its great-grandparent's vars...
If it gets all the way to window and nobody has a var of that name, then it creates one with that name on window.

function func1 () {
    var x = 0;

    function func2 () {
        var y = 1;
        x = 2;
        z = 3;
    }

    func2();
}

When you call func1, it sets its own x to 0, and calls func2. func2 sets its own y to 1. Then it sets func1's x to 2. Then, because func2 doesn't have z and func1 doesn't have z and window doesn't have z, it sets window.z to 3.

That's only the start of the confusion, and why its a very, very good idea to make sure that you're defining vars which need to be available inside of that function (and in any functions created inside of that function)... ...and when you reference pre-existing vars, you reference them carefully, and know where that var is supposed to be, in your code (which function defined it... ...so where on the chain the program is going to stop looking, before it gets to window), and why you're changing it from inside of another function.

Norguard
  • 26,167
  • 5
  • 41
  • 49
1

A common pitfall are loop counters - they are always named i and will collide. Example:

function a() {
    for (i = 0; i < 5; i++)
        b();
}
function b() {
    for (i = 0; i < 3; i++)
        ; // something
    // now, the /global/ i is reset to 3
    // … and the condition in function a will never be met
}
// so
a();
// is an infine loop instead of executing something 15 times
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Still trying to build the right brain pathways to think of this stuff on my own. Thanks for the example. – Benny Oct 09 '12 at 18:44
0

Unlike many C-style languages, JavaScript supports block syntax but does not support block scope, so the following may not run as you would expect:

var foo = 'bar';

{
  var foo = 'baz';
}

console.log(foo); // 'baz'

This is also evident in other JavaScript constructs that support blocks like if:

var foo = 'bar';

if (true) {
  var foo = 'baz';
}

console.log(foo); // 'baz'

Moreover, as Bergi pointed out, your i counters for fors will override each other because a for will not create a new scope.

Crockford considers JavaScript's lack of block scope an "Awful Part" of the language. Instead, JavaScript has lexical scoping, so only functions will create a new scope:

var foo = 'bar';

(function() {
  var foo = 'baz';
  console.log(foo); // 'baz'
}());

console.log(foo); // 'bar'

Every function in JavaScript has access to the variables in the function that contains it; inner has access to outer, but not vice versa. In the case of the above example, the IIFE (immediately-invoked function expression) has access to the foo = 'bar'; defined in the global scope, but instead we choose to override foo with a local var declaration and set it equal to 'baz'.

Bonus Point: Shog9 found that with can simulate block scope with an object literal like so:

var foo = 'bar';

with ({foo: 'baz'}) {
  console.log(foo); // 'baz'
}

console.log(foo); // 'bar'

Crockford discourages with due to its ambiguity, but if you really desire block scope, I see no harm in the with workaround.

Qcom
  • 18,263
  • 29
  • 87
  • 113