

All this, a comprehensive look at 'this' - halisaurus
http://bjorn.tipling.com/all-this

======
moron4hire
It's confusing to me to read through this and understand the nature of
variable declaration and reference in JavaScript with the emphasis on
demonstrating scenarios rather than describing the basic principles. I
understand though that some people would find this approach more useful than
my personally prefered approach. So don't take the rest of my post as
criticism, but addendum for folks who think differently.

I think "this" in JavaScript becomes much more clear (though only
subjectively) when you start playing with bind/call/apply.

There are three, separate contexts in JS. There is the declared function block
(Basic lexical scope, and other types of blocks don't create their own scope),
there is "this" context, and then there is the much less understood context
"with" which you're working (a sort of dynamic scope that is determined
lexically).

I call them "contexts" instead of "scopes", because "this" isn't a scope
level, and it is not contained in any scope level. It's a keyword that
references an object value that is determined by a different set of rules than
scope. If it were "in scope", then we could arrange scenarios in which we
could chain references to "this". There is no such thing as window.this, or
window["this"].

All variables (and named functions are function objects bound to a variable
name) are stored within an object somewhere. When you declare a variable, how
you declare it specifically sets the context object in which you're storing
the variable. "var x = 5", you're setting the variable on the function block
context. "this.x = 5", you're obviously setting on the "this" context. "x = 5"
declares the variable in the "with" context, if it's not already declared in
the function block. In all cases, it's first, "figure out some obj on which to
store this variable" followed by "set obj[fieldName] to value", where
fieldName is a string (always a string).

Accessing the variable again is the same sort of process. "Figure out what
containing object we're talking about, then access it as obj[fieldName]". In
all cases. The complexity lies in the figuring out step.

Now that we know that, we can start to ask questions about how these three
scopes are set.

Function block scope is always function block scope. Unless you create a new
function block (and only function blocks get their own scope level), then bare
variable references first check the function block scope. Also remember that
variable _declarations_ get "hoisted" to the top of the function. If you
declare a variable in a function, it's visible in the entire block. _But_ ,
the variable is not _set_ until the line on which it was originally declared.

    
    
        function(){
            console.log(x); // prints "undefined"
            //console.log(z);  would error, as no z is ever declared
            var x = "foo";
            console.log(x); // prints "foo"
        }
    

"with" scope is determined at the call site, by walking up the call lexical
scope until a declaration for the requested variable is found. If it gets all
the way up to the top "window" and it's still not found, you get an
"undeclared variable" error.

When you reference a function, what it will use as "this" then depends on
whether or not it was explicitly set with bind/call/apply, followed by where
it was found by the scope rules. If this wasn't set explicitly, then the
object in which the variable was stored is used as "this".

So that means, with respect to event handlers, that the handler functions must
be getting stored as a property of the DOM element to which they are bound.

But you can always override "this" with bind/call/apply. Just be careful that
you know what "this" means when you call "func.bind(this)".

It's not accurate, because the syntax suggests there is a higher context to
check, but if it helps you, you could think of the global script level in a
browser as:

    
    
        function window(){
            with(window){
                // all the code in your script block
            }
        }
        window.call(window);
    

Every "var" or bare or "this" declarations are going to get set on the window
object, every bare or "this" references are going to be from the window
object.

From there, a bare function call changes the function block scope, but not
"this" or "with". Calling with "new" changes function block and "this", but
not "with". And creating a with block changes changes "with", but not "this"
or function block. Calling "bind" sets "this" explicitly, and prevents it from
automatically changing--though it can be reset explicitly with another call to
bind. There is no way for one function block scope to have "this" change.

