Coffeescript Fat Arrow
I found myself in a situation where coffeescript was complaining that Object has no method foo when it clearly did. What is going on? Why is it so hard to call a class method from within a class?
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Car get_in_accident: -> @honk_horn("panic") @airbag() airbag: -> console.log("imma deploying mah airbag!") # just showing here that arguments don't change anything honk_horn: (level) -> if (level == "pissed") console.log("HONK HONK") else if (level == "panic") @yell("aaaa!", 1000) console.log("HON...") # the real issue is callbacks that lose the original scope yell: (message, wait_time) -> setTimeout -> console.log(message) @honk_horn("pissed") console.log("You jerk!") , wait_time car = new Car car.get_in_accident() |
What you see in this example is:
HON...
imma deploying mah airbag!
aaaa!
timers.js:103
if (!process.listeners('uncaughtException').length) throw e;
^
TypeError: Object # has no method 'honk_horn'
at Object._onTimeout (.:29:14)
at Timer.list.ontimeout (timers.js:101:19)
@honk_horn is supposed to refer to the instance variable when yell is called. It doesn’t know about it’s self? Well, there’s a good chapter about this (Chapter 6 of this book) on Binding and the Fat Arrow in coffeescript. It’s a simple fix to a confusing problem. The method that is called later (the callback method) needs to have a fat arrow => which generates a __bind function in javascript when the coffescript is compiled. This saves you a lot of time and effort. All you have to remember is to use the fat arrow when a callback is going to be called out of scope.
So just change the setTimeout line to have a => instead of ->:
|
1 2 |
yell: (message, wait_time) -> setTimeout => |
Now it works right. Also notice that the “aaaa!” yell is happening before the “HON…” log statement in both examples.
HON...
imma deploying mah airbag!
aaaa!
HONK HONK
You jerk!