9

Is it better to do,

asset.addEventListener("load", function () {
  this.emit({
    type: "load",
    asset: asset
  });
}.bind(this), false);

Or

var scope = this;

asset.addEventListener("load", function () {
  scope.emit({
    type: "load",
    asset: asset
  });
}, false);

Is it better to bind the function, or just store the reference to this in a variable?

hexacyanide
  • 88,222
  • 31
  • 159
  • 162
user2251919
  • 665
  • 2
  • 11
  • 23
  • 1
    What do you mean by "better"? Faster? – TimWolla Jun 21 '13 at 18:15
  • 1
    @DanyCaissy Jquery is not the answer to everything, especially wanting to learn fundamental javascript, if everyone just used Jquery who would create new awesome libraries, I am sure before Jquery got released every said just use someLibrary, but if the creator of Jquery did that there would be no Jquery! – user2251919 Jun 21 '13 at 18:19
  • @user2251919: It is for people that are helpless without it! –  Jun 21 '13 at 18:20
  • 1
    @CrazyTrain And the only way to become useful without it, is to not use it! – user2251919 Jun 21 '13 at 18:21
  • Please move jQuery discussion to chat. – showdev Jun 21 '13 at 18:21
  • @user2251919: Exactly. Point was that fanboys that go around telling everyone to use jQuery are usually helpless without it. –  Jun 21 '13 at 18:22
  • @CrazyTrain I agree with that comment 100%, Jquery has its uses, but I still like to create things rather than create things from created things :) – user2251919 Jun 21 '13 at 18:26

4 Answers4

4

It really depends on a number of factors. Here are a few considerations:

  • Historically, functions created from .bind() have been slower.

  • The bound this can't change its value, while the variable can. (Guessing you expect it to not change here.)

  • You'll be losing the element reference, though you can still get it via event.currentTarget.


One other alternative to consider is to make your object implement the Event Listener interface. That will let you pass the object itself as the handler, and will invoke your implementation of the handleEvent() method that you provide.

Then the this value will automatically be your object.

So if your this is an object that comes from a constructor, you could do this:

function MyCtor() {
    // your constructor
}

// This implements the `Event Listener` interface
MyCtor.prototype.handleEvent = function(event) {
          // ------v----should be "load"
    return this[event.type](event)
};

// This is the `load` handler
MyCtor.prototype.load = function(event) {
    this.emit({
      type: "load",
      asset: event.currentTarget
    });
};

And then bind the handler like this:

asset.addEventListener("load", this, false);

Now your value of this in the handle event will be your object so you can call its other methods, and neither .bind nor a closure variable were needed.

2

I feel that the second option is better, just to prevent any confusion. The usage of this has been the problem of many a JavaScript problem, so when you can avoid it you should in my opinion. By the way, this is also done in libraries like Knockout.

If you'd like to know more about the this keyword, this is a nice explanation of the various different values this can have in different contexts: http://javascriptweblog.wordpress.com/2010/08/30/understanding-javascripts-this/

Erik Schierboom
  • 16,301
  • 10
  • 64
  • 81
  • I am still learning and there are so many ways to do things it gets a little confusing! Thanks for your answer. – user2251919 Jun 21 '13 at 18:20
0

The second option is compatible with more browsers. The bind() function is not supported by IE 8 and below, if that matters to you.

Mozilla's page on bind has a pollyfill for the bind function. In my experience it's usually a bad idea to add to the prototype of builtin objects. So the second option is "better" - just make sure to use a descriptive variable name instead of "that" or "scope". Using a common name can get confusing, especially when you add more functions.

Luke
  • 13,678
  • 7
  • 45
  • 79
  • What could be bad about filling in a missing method in an old browser? –  Jun 21 '13 at 18:59
  • @CrazyTrain The extension isn't private, and shows up in `for in`. See [this question](http://stackoverflow.com/questions/1107681/javascript-hiding-prototype-methods-in-for-loop). One of the biggest reason jQuery is favored over Prototype. – Luke Jun 21 '13 at 19:01
  • Extensions are never "private", but yes, they can be enumerable, and can break poorly written code. Why anyone would be using `for-in` on a function object is beyond me. And when they do it on Arrays, they're simply using the wrong tool. –  Jun 21 '13 at 19:02
-1

None of them, because both create anonymous functions that you can never remove later.

var scope = this;
var handler = function () {
  scope.emit({
    type: "load",
    asset: asset
  });
};

asset.addEventListener("load", handler, false);
Alessandro Vendruscolo
  • 14,493
  • 4
  • 32
  • 41
  • Why would you want to remove the listener? – gen_Eric Jun 21 '13 at 18:21
  • But in terms of binding and not binding? – user2251919 Jun 21 '13 at 18:22
  • 1
    The question isn't really about listeners. It's about closure references vs bound `this` references. –  Jun 21 '13 at 18:25
  • I'm afraid this fails to answer the question. Using anonymous listeners (or not) is orthogonal to whether or not to use bound functions or outer variables. All four combinations are valid possibilities (named/bound, anonymous/bound, named/outer-variable, anonymous/outer-variable). – apsillers Jun 21 '13 at 18:54
  • 1
    I know that the question refers to bind/outer-this, but IMHO, anonymous event handlers should be taken with care. Also, in the answer, it's stated how I'd approach the problem (which is, by saving the scope in an outer `var`). – Alessandro Vendruscolo Jun 21 '13 at 20:42
  • 1
    You've certainly *used* an approach, but you haven't *advocated for* an approach. It is unclear whether your choice to use an outer variable was chosen deliberately or arbitrarily, since you don't provide justification for it in the text of your answer. I agree that your suggestion not to use anonymous listeners is helpful advice -- it would make a great footnote or comment -- but it does not address the actual question. – apsillers Jun 21 '13 at 20:47