User:MarkTraceur/JavaScript Scoping

From mediawiki.org

Short tutorial on scoping and this usage in JavaScript - meant for education, not documentation or prescription.

When you write something like

function blah() {
}

It creates a scope. When, inside it, you type another function, it creates a totally separate scope.

function blah() {
    function foo() {
    }
}

Writing two separate scopes can be immensely useful - you can have two variables with the same name and separate values. e.g.,

function blah() {
    var i = 0;
    function foo() {
        var i = 'a string';
        // Here, i is 'a string'
    }
    // Here, i is still 0.
    foo();
    // i is still 0 here!
}

Inner scopes are also useful because they can have different contexts. In JavaScript, context is represented in the "this" variable.

function blah() {
    this.thing = 1;
    function foo() {
        this.thing = 2;
        // this.thing is 2
    }
    // this.thing is still 1, even if I called foo
}

The context variable is set, by default, to the Function object that was just called. But you can call it with a different context by making the function a method of an object, or, by using Function.prototype.bind or an equivalent.

var thing = {
    blah: function () {
        this.thing = 1;
        // thing.thing is now 1
    }
};

When you want to pass a function as a callback, or any other argument, you might run into troubles using the context variable(s), because they change when the new scope is created. The function you pass into another function might get called with an unknown object as its context, with some other value, or with exactly what you expect. The easiest way to avoid issues of this type is to use a local copy of the outer context in an inconspicuously named local variable.

var thing = {
    blah: function () {
        var something = this;
        doSomethingWithCallback( function () {
            something.foo();
        } );
    },
    foo: function () {
        // do something
        this.doSomething();
    }
};

However, when you're doing this, it can be tempting to use "something" instead of "this", which is less expressive. Instead, use "this" in the outer context and "something" only when necessary.

var thing = {
    blah: function () {
        var something = this;
        // Not something, this
        this.checkValid();
        doSomethingWithCallback( function () {
            // Scope changed, so, not this, something.
            something.foo();
        } );
    },
    foo: function () {
        // do something
        this.doSomething();
    }
};