Hacker News new | ask | show | jobs
by willvarfar 4998 days ago
The big bug as I see it is:

   obj = {
     get_name = function() { return "I am an object" },
     func = function() { alert(this.get_name()); }
   }
This looks dandy, and obj.func() works as expected.

but if you pass obj.func as a callback, the this when its invoked will be some other object (by default, the window object):

   button.onclick = obj.func; // bang when invoked
The number of times I got screwed by that. You end up having to have little anonymous functions for all callbacks:

    button.onclick = function(evt) { obj.func(); }
(apologies for bugs; just typing javascript from memory)

(would love to be wrong)

3 comments

It clicked for me when I decided that there were no methods and considered all function invocations to be special cases of `apply`. Then the case you mentioned becomes a bog standard case of a property lookup, and the callback becomes a case of `apply(window, [args])`.

tldr: JavaScript has functions, not methods :)

This is exactly the catch with respect to function invocation method that I was trying to point out. It seems that in a call back method, `this` gets bound to the global object. I suspect it is because it is called with the same mechanism that is used for function invocation. That being said, I did not use this example because one needs to implement a callback to see the error. My example that I chose in my article was designed so that anyone could just create the JavaScript, fire it up in a browser, and see the error for themselves.

I do however intend to use an example similar to the one you have presented when I cover closures and scoping in JavaScript.

bind was introduced in ES5 (and previously in most libraries) to fix this

https://developer.mozilla.org/en-US/docs/JavaScript/Referenc...

And trivially easy to shim for older browsers. I would really recommend using Function.prototype.bind instead of the 'var self = this' or library bind functions (such as $.proxy), it's just the way it should be written :)
To confirm my understanding, would the erroneous line from the comment above be rewritten like:

    button.onclick = obj.func.bind(obj);
So un-DRY! It's almost admirable, how blatant a hack this is.