Hacker News new | ask | show | jobs
by asolove 5046 days ago
While the syntax here is CoffeeScript-specific, this is a perfectly fine pattern to apply in any JavaScript.

The key is to remember that, in JavaScript, you aren't really "defining instance methods" in the way you are in almost any other language. You're just passing anonymous functions as the value tied to some key in a dictionary, which happens to be the prototype of some set of objects. Once you get that into your mind and let it play around for a bit, you realize that you could be getting the anonymous function from anywhere!

From a function-factory, that takes some arguments and returns a function:

    render: renderWithTemplate("some_template")
From an anonymous function wrapped in something that controls its execution:

    onScroll: _.debounce(100, function(){ /* do something */ })
Or even by delegating to another object:

    viewInstance.onScroll = _.bind(somethingElse.render, somethingElse);
Thanks for the great post to help bend our minds around these possibilities.
1 comments

> Or even by delegating to another object:

> viewInstance.onScroll = somethingElse.render;

This one is a bit dangerous, because as you mention the "methods" are just anonymous functions assigned to objects. If `render` is expecting to be called on a `somethingElse`, this might not work right without being bound.

That's why I never use "this" in Javascript. For me, dropping any pretense of OOP allows me to write more elegant programs.
I think that's a pretty poor practice. It's actually counter to central idea of this article; that you should think with the language features. In situations like the one above, if you dont want to lose the context of "this" you can explicitly bind an object to be this and return the new bound function. See underscore's bind(). Its a little more verbose and clunky but it saves you from tossing out modular code.
I'm not so sure it's poor practice. Rich Hickey makes an excellent point about not confounding data and functions. And Javascript provides excellent structures for avoiding mutability altogether (if one wishes to) thanks to first-class functions. Javascript was always an amalgam of C-syntax, object-oriented "ideas", and functional "ideas". To "think with the language features" is to tie to together two disparate programming paradigms that in my opinion perform better independently than in combination. So I just happen to focus more on the functional aspects of Javascript (and CoffeeScript provides syntactic support to make this much easier).
Not poor practice in that Functional Programming is poor practice (it's great practice!). Poor practice in that JS is object oriented and JS engines optimize for OO style, see https://developers.google.com/v8/design for example. So avoid `this` if you don't care how fast your code runs.
> See underscore's bind()

Better, just use Function.prototype.bind, 0 bytes gzipped with Vanilla JS.

And of course, in CoffeeScript you would just use the fat arrow:

    somethingElse =
      render: => # do some rendering
Careful, that's not the same as (->).bind(somethingElse). => binds to the current value of this at execution-- in that function, @ will compile to `var _this = this`, not `somethingElse` as we'd expect.

I just tested and it looks like you can hack it by doing

  _this = somethingElse =
    render: => @renderMe # @ is somethingElse
but that is definitely a bug.
I've written some transpilers, and I nearly always use a "magic variable" like __this_12345 just to prevent problems like--umm--this. If every single one you use has a quasi-random number or string appended, a lot of headaches melt away.
Yeah, I apologize. I have changed it to read correctly.