0

Given the following, common scenario:

console.log(this); // window or any parent object

$('.selector').on('click', function(event) {
    console.log(this); // clicked DOM element
});

var myFunc = function() {
    console.log(this); // window or parent object
}

Since version 1.3 jQuery adds the event.currentTarget when binding event handlers for which counts event.currentTarget === this, so is there actually a good reason to manipulate this and switch context? Doesn't this behaviour generally go against the unspoken rule of "don't change keyword values" (like undefined = 'not defined')?

This "feature" of jQuery makes a lot of OOP less efficient and awkward imho, when we need to either cache the original this in a variable like self or use helpers like jQuery.proxy to reassign context to event handlers.

My question: is this just a relic of early jQuery implementations kept alive or is there an actual benefit which I cannot see (except maybe the slightly more convenient way than accessing event.currentTarget to get the element...)?

Simon
  • 7,182
  • 2
  • 26
  • 42
  • 1
    What do you mean by 'manipulate'? I don't see how `this` is being manipulated in your example. – j08691 Oct 03 '14 at 13:35
  • Because jQuery is dispatching to the registered event handler, `this` is inevitably going to be under its control. It's hard to imagine any other value for `this` as making more sense than the relevant DOM node. – Pointy Oct 03 '14 at 13:37
  • 1
    Note that `this` is quite different from `undefined` - the circumstances of *every* function call *always* determine the value of `this` for that call. You cannot call a function without affecting the value of `this`, in other words. – Pointy Oct 03 '14 at 13:38
  • @Pointy Not in OOP, since you can access any relevant DOM node through the event object, which is always given with jQuery event handlers... – Simon Oct 03 '14 at 13:38
  • 3
    JavaScript is not like other OOP languages! – Pointy Oct 03 '14 at 13:39
  • Still your point is not valid, because just defining an anonymous function does not change context... I'll add an example. – Simon Oct 03 '14 at 13:40
  • 4
    Yes, **defining** an anonymous function does not change context, but **calling** the anonymous function most certainly does (unless you explicitly arrange for `this` to be the same as the calling context via `.call()` or `.apply()`). That's just how JavaScript works. – Pointy Oct 03 '14 at 13:41
  • 1
    I think it makes sense that `this` refers to the DOM element, since that's how native event handlers work as well. http://www.quirksmode.org/js/this.html – Felix Kling Oct 03 '14 at 13:45
  • `this` isn't like `undefined` because `undefined` has a constant meaning in all cases: it means it's not defined. `this` is supposed to vary from one context to another, hence the name. When calling methods on a well-known object, that's one thing, but for callbacks in particular, it's ambiguous as to what `this` could be. It could even be `undefined` or `null` or `global`. It's nice that jQuery picks a specific, non-ambiguous value for `this` and documents it. – Brandon Oct 03 '14 at 13:45

2 Answers2

4

Let's say you've got an object with some methods on it:

var object = {
  click: function() {
    alert(this.property);
  },

  property: "Hello World"
}

You can call object.click() and, as you'd expect, you'll get "Hello World" in the alert.

You'd like to be able to use that "click" function as an event handler:

$("button").on("click", object.click);

However you discover that that doesn't work, because jQuery invokes the "click" function with this set to the DOM node for the clicked button. This is irritating. It's also inevitable because of the semantics of JavaScript function calls.

When you call the "click" function by way of a property reference, the language arranges for this to refer to that object. That's why object.click() works. However, when you fetch the reference to the function and pass it across a function boundary (as in the call to .on()), that relationship is lost. All that the jQuery method gets is a plain unadorned function that has absolutely no inherent relationship to the original object involved in its definition.

Thus, jQuery really has only two choices. The first is that it could make explicit the fact that the function is unconnected by arranging for this to be undefined. That wouldn't be very useful however. The other choice is to pick something interesting for this, and that's what the library does. Note that the native DOM level 0 event dispatch mechanism does the same thing.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • This is good rationale for why the native javascript behavior was designed the way it was. – slebetman Oct 03 '14 at 13:51
  • Ok accepted this as answer, thx for the insight. Just a note: changing `this` is not native JavaScript but DOM, there's a difference. – Simon Oct 03 '14 at 14:24
  • @Simon: *"changing `this` is not native JavaScript but DOM, there's a difference"* Not sure what that's supposed to mean, but DOM has nothing to do with `this`. – Felix Kling Oct 03 '14 at 15:15
  • DOM has all to do with `this`. Everything concerning events (including event listeners) is part of the DOM, not Javascript, we only use Javascript to handle events. Something like `element.addEventListener` doesn't exist in [native JS](https://github.com/tmpvar/jsdom). Just wanted to make that clear. – Simon Oct 03 '14 at 15:50
  • @Simon yes, that's true, but the basic workings of `this` don't have anything in particular to do with the DOM. It's part of the definition of the language itself. Things are exactly the same in Node.js for example, and there's no DOM in Node.js. – Pointy Oct 04 '14 at 05:01
2

The reason is that jQuery wants to mimic how regular event handlers (ones created without jQuery or any other library) works. In regular event handlers the value of this refers to the DOM node that triggers the event if there is one.

One could in fact consider that this is an example of jQuery not manipulating built-in behavior.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • 1
    As usual with this types of questions (pun intended) refer to my answer to this related question to understand how `this` works in javascript: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 – slebetman Oct 03 '14 at 13:49