I have come across this construct a few times.
Example 1:
_ = require 'underscore'
class Controller extends App
_doSomething: _.throttle (event) ->
$div = $(event.target).closest 'div'
...
My Question:
I have trouble understanding why this construct is valid.
Normally a class function definition goes like:
_doSomething: (event) ->
$div = $(event.target).closest 'div'
...
, 500
So how can _.throttle sit in between : and (event) the function parameter?
If _.throttle is supposed to act as an wrapper, shouldn't it be written as
_doSomething = _.throttle( (event) -> # an anonymous function that takes event as parameter
$div = $(event.target).closest 'div'
...
, 500
Things might be clearer if we add the optional parentheses:
class Controller extends App
_doSomething: _.throttle( (event) ->
$div = $(event.target).closest 'div'
...
)
Now we see that _.throttle is function call and it is being given an anonymous function as its single argument. We can break it down a bit more to further clarify what's going on:
f = (event) ->
$div = $(event.target).closest('div')
...
throttled_function = _.throttle(f)
class Controller extends App
_doSomething: throttled_function
_.throttle returns a function so the code you're looking at just just a complicated version of:
class Controller extends App
_doSomething: some_function
which is nothing special. Keep in mind that you can use anonymous functions when building a class's methods but named functions or other expressions which evaluate to functions serve just as well; the syntax is really:
name: expr
where expr is some expression and f(x) (or _.throttle(some_anonymous_function)) is an expression.
Related
The title says it all. When I use the fat-arrow in CoffeeScript, it stores this first before calling the function. For example:
class myClass
constructor: ->
element = $ "#id"
element.click ->
#myMethod(#value)
return
return
myMethod: (c)->
window.console.log(c)
return
would yield
var myClass;
myClass = (function() {
function myClass() {
var element;
element = $("#id");
element.click(function() {
this.myMethod(this.value);
});
return;
}
myClass.prototype.myMethod = function(c) {
window.console.log(c);
};
return myClass;
})();
Now on line#8 of JavaScript, this.myMethod is wrong. In this scope, this refers to element instead of the class MyClass.
However, if on line#4 of CoffeeScript, I replace element.click -> by element.click => the line#8 in JavaScript will become _this.myMethod(_this.val) where this referring to myClass is stored in _this before calling the function. But _this.value is undefined and even if it were defined, the object I'm trying to access here is element (which is referred to by the actual this keyword in scope of this function).
How would access the actual this now?
You can achieve your goal in at least three ways. The 1st one would be:
class myClass
constructor: ->
element = $ "#id"
element.click =>
#myMethod(element.value)
return
return
myMethod: (c) ->
window.console.log(c)
return
And the 2nd:
class myClass
constructor: ->
element = $ "#id"
myMethodCallback = (c) => #myMethod(c)
element.click ->
myMethodCallback(#value)
return
return
myMethod: (c) ->
window.console.log(c)
return
The 3rd one is as showed below. I'm not sure about jQuery API usage though, so better check on appropriate docs page.
class myClass
constructor: ->
element = $ "#id"
element.click (event) =>
#myMethod(event.target.value)
return
return
myMethod: (c) ->
window.console.log(c)
return
I would prefer the 1st way as it seems to be more straightforward.
This or the other but you need to decide 'which this' you would like to have in scope of the element.click callback. It's not possible to access two 'thises' at the same time.
By the way. All those return statements seems unnecessary. The shortest working solution would look like:
class myClass
constructor: ->
element = $ "#id"
element.click => #myMethod(element.value)
myMethod: (c) -> window.console.log(c)
This works :
class Foo
class #_Bar
#narf = ''
#point : ->
#narf = 'what'
class #_Baz extends #_Bar
#point : ->
#narf = 'woo'
super()
This does not
class Foo
class #_Bar
#narf = ''
#point = ->
#narf = 'what'
class #_Baz extends #_Bar
#point = ->
#narf = 'woo'
super()
running Foo._Baz.point() will throw and error.
Please someone explain what is going on here.
It seems like a bug in the compiler to me. Writing
class X
#classMethod: ->
and
class X
#classMethod = ->
should be equivalent, yet super compiles differently across the two methods. In the first, it compiles correctly:
X.__super__.constructor.classMethod.apply(this, arguments);
In the second, it compiles as if classMethod were an instance method:
X.__super__.classMethod.apply(this, arguments);
This works:
class Foo
class #_Bar
#narf = ''
point : ->
#narf = 'what'
class #_Baz extends #_Bar
#point = ->
#narf = 'woo'
super()
alert Foo._Baz.point() # 'what'
alert new Foo._Bar().point() # 'what'
That is, the compiled #point= super ends up pointing to the instance point:. Its JS is: _Baz.__super__.point.call(this), which is _Bar.prototype.point.call(this). (extends defines: child.__super__ = parent.prototype).
It's clear from past Coffeescript changes that #point: is the intended syntax for static (class) methods (and used that way in the compiler itself).
There are a couple of fixes now on github. https://github.com/jashkenas/coffee-script/issues/3232
Currently the node tree for a #foo= method is different from that of a #foo: method. Because of that, a node created with = is never passed to the Class addParameters method, and is never flagged as static.
One solution, which will probably be accepted, makes sure both forms produce the same node tree.
The one I contributed https://github.com/jashkenas/coffee-script/issues/3232#issuecomment-28316501
adds a method to nodes.coffee class Class. This method is a stripped down version of addParameters, and specifically checks a = node tree.
If you need a fix in your own Coffee compiler, modify your src/coffee-script/nodes.coffee file, compile it, and put the resulting node.js in the lib directory (or use the cake build).
I have a "class" in coffee script whose instance variables I want to initialize with instance methods that return a value via a callback, but it doesn't work as I had hoped:
EventEmitter = require('events').EventEmitter
class MyClass extends EventEmitter
constructor: ->
#datamember: setDatamember()
setDatamember: ->
someFunction (response) ->
#datamember = response
#emit 'init'
getDatamember: ->
return #datamember
----
myObj = new MyClass
myObj.on 'init', ->
console.log myObj.getDatamember
The result I get suggests that "this" in setDatamember is referring to something different from what "this" refers to in the object instance. If I explicitly call myObj.setDatamember, I get the expected result, but is there any way to call on a set method -- specifically one that sets the data member via a callback -- in the constructor? I've looked through the docs, as well as various other sources of coffeescript info (e.g. this one), and I haven't found anything that touches upon this.
Try using a fat arrow for the anonymous function:
setDatamember: ->
someFunction (response) =>
#datamember = response
#emit 'init'
Also, you'll need to call the correct function in the constructor:
constructor: ->
#setDatamember()
In general, avoid fat arrows on methods - the way Coffee-Script implements this does some bad things to memory usage. Also, it will rarely be necessary.
However, anonymous functions that refer to this will almost always need fat arrows. this is not held in closure like normal variables, and will only be set by binding (Function.prototype.bind) or by calling it as an object method (obj.myMethod() will set this to obj in myMethod).
Try using fat arrows on everything except the constructor:
class MyClass
constructor: ->
#setDatamember()
setDatamember: =>
someFunction (response) =>
#datamember = response
getDatamember: =>
return #datamember
However, you also look to have someFunction in there as an asynchronous function, so you'll never be able to just do
mc = new MyClass
console.log mc.datamember
Because that doesn't wait for someFunction to return before accessing mc.datamember.
I started writing coffeescript last week, as I am programming a new Play20 site where coffeescript is the standard. I want to update a getData function in my class every 5 minutes, but the setInterval function does not bind to my class. Only the first time it calls getData, because the 'this' object is still reachable, as the setUpdateInterval() function is called from within the constructor.
But after the first call, the setInterval does not have any connection anymore with the Widget instance, and does not know what the this.getData() function is (and how to reach it).
Does someone know how to do it?
Here is my code:
class Widget
constructor: (#name) ->
this.setUpdateInterval()
getData: ->
console.log "get Data by Ajax"
setUpdateInterval: (widget) ->
setInterval( this.getData(), 3000000 )
Now here some Javascript magic is required. Reference
class Widget
constructor: (#name) ->
this.setUpdateInterval()
getData: ->
console.log "get Data by Ajax"
setUpdateInterval: (widget) ->
callback = #getData.bind(this)
setInterval( callback, 3000000 )
This will work in almost all browsers (guess which one not), so the
function will have to be bound differently. Some coffeescript magic:
callback = => #getData
The problem is that you are executing the function, instead of passing a reference to it.
Now, it sounds like you need to also keep the scope of the instance. do and => can help with that.
setUpdateInterval: (widget) ->
setInterval (do =>
#getData), 3000000
true
compiles to
Widget.prototype.setUpdateInterval = function(widget) {
var _this = this;
setInterval((function() {
return _this.getData;
})(), 3000000);
return true;
};
you will note the code executes a self invoking function, which return a function, that creates a closure around this, locking it into the scope of the callback (as _this)
Also note that you don't need to pass widget to the method (you aren't using it anywhere), and you would invoke this function in your constructor, to set up the interval. Whatever you do, you only want to call this method once. You could just put the contents of the function in your constructor.
Finally, since coffeescript returns the value of the last statement from all functions, I throw a true in there, but that might no be necessary.
This is handy in node as well. It's a varient of Tass's answer.
class Widget
constructor: (#options = {}) ->
#options.interval ?= 1000
#setInterval()
timer: ->
console.log 'do something'
setInterval: ->
cb = #timer.bind #
setInterval cb, #options.interval
w = new Widget()
class #A
A_Function_Alias: => #my_function
my_function: =>
usage_of_alias: =>
#A_Function_Alias.call()
What i want, is usage_of_alias to be
usage_of_alias: =>
#A_Function_Alias
And have it behave the same. i.e. I want a more functional style syntax here. I've tried multiple combinations with no success. The fact that i have to evaluate my function to get the goodies inside bothers me.
One application would be instead of this:
event: => new Event(#my_function)
which is accessed as event.call().hi()
i could have some other declaration that would allow me to access event as event.hi()
Something that behaves more like a field instead of a property.
I'm thinking you want this:
class #A
my_function: => alert 'my function!'
A_Function_Alias: #::my_function
usage_of_alias: =>
#A_Function_Alias()
# some other code...
See what this compiles to here.
When evaluating a class # is the class constructor object, the class object itself. And the :: operator lets you drill into the prototype. So #::foo in a class body compiles to MyClass.prototype.foo.
So what this is doing is first making a normal instance method named my_function, defined on A.prototype.my_function. Then we make a new instance method named A_Function_Alias and directly assign the function from class objects prototype that we just created. Now my_function and A_Function_Alias both point to the exact same function object.
But as a more sane alternative, might I suggest a pattern that defines a private inner function that the class can use, and then assigning it more directly, without crazy the prototype accessing?
class #A
# Only code inside this class has access to this local function
innerFunc = -> alert 'my function!'
# Assign the inner funciton to any instance methods we want.
my_function: innerFunc
A_Function_Alias: innerFunc
usage_of_alias: =>
#A_Function_Alias()
# or
#my_function()
# or
innerFunc()
# they all do the same thing