Hacker News new | ask | show | jobs
by moron4hire 4320 days ago
Don't think of "this" as having weird rules with strange edge cases about what it defaults to in certain scenarios. It is always dependent on how you call the function, and there are only two rules, depending on your situation.

    1) "this" is whatever you set it to with call/apply/bind, or, if you didn't,
    2) if you're using "use strict"
    2.a) "this" is whatever is to the left of the dot when you call the function.
    2.b) otherwise, "this" is wherever you got the function from. 
Think of 2.a in the literal sense, if you called the function from a bare variable reference with no dot operator on an object, then the statement "whatever is to the left of the dot" is "undefined". Basically, this means that you generally shouldn't end up with "window" as "this".

So, if you got a function from the global scope, it's "this" is in the global scope. If you got it from an object, it's "this" is that object.

    function AClass(){ this.id = "bar"; }
    AClass.prototype.func = function(){ console.log(this.id); };
    var id = "foo";
    var obj1 = new AClass();
    var obj2 = {id: "baz"};
    var func = obj1.func;
    obj2.func = obj1.func; // or even just "func"

    console.log(func === obj1.func, func === obj2.func, obj1.func === obj2.func);

    func();      // prints "foo"
    obj1.func(); // prints "bar"
    obj2.func(); // prints "baz"
    with(obj1){ func(); } // prints "bar"
    with(obj2){ func(); } // prints "baz"
Same exact function in all cases. The reason func's "this" in the first of the last three calls is "window" is not because that's what "this" defaults to, it's because that's where we found "func".

Think of the global scope in a browser as looking something like this:

    function window(){
        with(this){
            // your code
        }
    }
    window.call(window);
So that is why, when an event handler is executed, it's "this" is the DOM element to which the event handler was added.

    myButton.onclick = function(){
        // do something
    }
You just stored the function on the myButton object, so when it gets read back again to be executed, it's coming from myObject.

Using addEventListener does the same thing. And if the browser vendors don't actually store the event callbacks in the object, then I guess they must be using "call" to maintain backwards compatibility with the old event wiring syntax.