JavaScript scopes

JavaScript scopes

Not your average block-level scope

I started my programming career with C, C++/VC++, and then Java. All are known as C family languages and they all share block-level scope when it comes to variables and function declarations. In other words, each block, typically represented by { and } braces, creates a new scope. For e.g.

#include <studio.h>

int main() {
    int a = 1;
    printf("%d ", a); //1

    if(1) {
        int a = 2;
        printf("%d ", a); //2
    }

    printf("%d ", a); //1
}

Scope of int a variable declared inside if block exists only till the end of if block.

However, when I started working with JavaScript I tripped real hard understanding scopes in JavaScript. JavaScript's C family-like syntax had me fooled. The thing is JavaScript scopes are fundamentally different as they are defined by functions, not by blocks. For eg.

function a() {
    console.log(typeof b); // prints 'function'
    if(1) { 
        function b() {};
    }
    console.log(typeof b); // prints 'function'
}
a(); // prints 'undefined' as expected

Here function b is accessible i.e. prints 'function' even after the if block ends. In fact, function b can also be forward referenced before the if block. This is known as function hoisting.

Here comes the tricky part though. Variables declarations in JavaScript are in scope from their point of declaration inside a function till the end of the function, irrespective of block nesting. For e.g.

function a() {
    console.log(typeof b); // prints 'undefined' because var b is not in scope yet
    if(1) { 
        var b = 1; // var b will be in scope till the end of function a
    }
    console.log(typeof b); // prints 'number'
}
a(); // prints 'undefined' as expected

Notice that unlike function b in previous sample code, var b here can not be forward referenced.