0

Why does calling an object function straight from an addEventListener make this point to calling element, but calling from a third party function makes this point to the object and NOT the third party function?

var obj = {
    me: 'obj',
    objFunction: function(){
        document.body.innerHTML += this.me;
    }
};

document.addEventListener('mousedown', obj.objFunction);
document.addEventListener('mouseup', thirdParty);

function thirdParty(){
    obj.objFunction();
}

The above code will print undefined on mousedown and 'obj' on mouseup. http://jsfiddle.net/ana353Lk/1/

Guess I'm curious if there is an advantage to why it works this way...

Qantas 94 Heavy
  • 14,790
  • 31
  • 61
  • 78
user2782001
  • 2,928
  • 2
  • 15
  • 32
  • See also [How to access the correct `this` / context inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback) and the documentation about `this`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this and [Using this inside an event handler](http://stackoverflow.com/q/17665489/218196) – Felix Kling Aug 19 '14 at 02:58
  • @slebetman: This is not a duplicate of that question. – Felix Kling Aug 19 '14 at 03:00
  • @FelixKling: While the question is not a duplicate of this question the answer is also an answer to this question. Which in Stackoverflow is the definition of "duplicate". – slebetman Aug 19 '14 at 07:00
  • @Qantas94Heavy: My answer is more complete and more frequently updated : http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal – slebetman Aug 19 '14 at 07:01

2 Answers2

2

When you do this:

document.addEventListener('mousedown', obj.objFunction);

You are only passing a reference to the objFunction function. There is no reference at all to obj passed. So, when the event system calls the callback objFunction is just calls it as a normal function no different than this:

 var fn = obj.objFunction;
 fn();

Thus, the context of the object is lost entirely and the method is just called as if it was a normal function. There are several work-arounds.

document.addEventListener('mousedown', function(e) {return obj.objFunction(e)});

or

document.addEventListener('mousedown', obj.objFunction.bind(obj));

Both of these work-arounds create a small stub function that is what the event handler calls and then the stub turns around and calls obj.objFuntion() with the appropriate object reference which causes this to be set to obj.


In case you aren't familiar with how this is set in javascript, it's worth some reading on that. Here's one reference and another reference. How this is set is determined by how a function is called (not by how the function is defined). In a nutshell, there are these cases:

  1. Normal function call fn() - this is set to the global object or undefined (in strict mode).

  2. Method call obj.method() - this is set to obj inside the method.

  3. Using fn.apply(x) or fn.call(x) - this is set by the first argument to .apply() or .call().

  4. Using var newFn = fn.bind(x) - When newFn() is called, this is set to the first argument passed to .bind().

  5. Using new with a constructor function as in var x = new Fn(); - In the constructor function this will be set to a newly created object of the Fn type.

jfriend00
  • 580,699
  • 78
  • 809
  • 825
0
var bind = function bind(context, name) {
    return function () {
        return context[name].apply(context, arguments);
    };
};

var obj = {
    me: 'obj',
    objFunction: function () {
        document.body.innerHTML += this.me;
    }
};

document.addEventListener('mousedown', bind(obj, "objFunction"));
document.addEventListener('mouseup', thirdParty);

function thirdParty() {
    obj.objFunction();
}
Greck
  • 82
  • 7