I have following CS code snippet:
class Ctrl
constructor: (@security) ->
...
isAuthenticated: -> @security.isAuthenticated()
which is translated to following JS:
Ctrl = (function() {
function Ctrl(security) {
this.security = security;
...
}
Ctrl.prototype.isAuthenticated = function() {
return this.security.isAuthenticated();
};
})()
As you can see isAuthenticated is a simple delegation to security object's method and creating anonymous function is redundant.
I want to avoid creating this additional call level and instead perform kind of 'inline delegation' which would translate to JS similar to:
Ctrl = (function() {
function Ctrl(security) {
this.security = security;
...
}
Ctrl.prototype.isAuthenticated = this.security.isAuthenticated;
})()
Following doesn't work, since it tries to bind @security to wrong object:
class Ctrl
constructor: (@security) ->
...
isAuthenticated: @security.isAuthenticated
Any clues ?
You can hook up delegation in various ways but you have to be aware of two things:
@ is when you're hooking up the delegation.@security.isAuthenticated probably won't work if isAuthenticated is called with a this that isn't @security.(1) tells you what you need to attach the delegate functions to (see below). (2) is the usual "a function reference isn't really a method" problem in JavaScript; for example:
o =
m: -> console.log(@)
o.m() # Puts `o` in the console
f = o.m; f() # Puts `window` (usually) in the console.
So you have to keep isAuthenticated bound to @security or it probably won't work.
One simple way to add delegation is to attach a bunch of bound functions to @ inside the constructor:
delegate = (to, from, methods...) ->
for m in methods
to[m] = from[m].bind(from)
class Ctrl
constructor: (@security) ->
delegate(@, @security, 'isAuthenticated', 'somethingElse')
Then you can say:
c = new Ctrl(s)
c.isAuthenticated()
c.somethingElse(11)
and the expected things happen. Demo: http://jsfiddle.net/ambiguous/we8gT/
One problem with that approach is that each instance of Ctrl ends up with its own isAuthenticated and somethingElse functions: they're not attached to the prototype so they're not shared.
But we can always create our own functions and take advantage of the fact that we can call code inside class C:
delegate = (klass, property, methods...) ->
for m in methods
do (m) -> klass::[m] = (args...) -> @[property][m](args...)
class Ctrl
delegate(@, 'security', 'isAuthenticated', 'somethingElse')
constructor: (@security) ->
A few things of note:
:: is used to access the prototype so the methods will be shared.(args...) -> to pass any arguments through to the @security method.@ at the class level is the class itself.do to ensure that m is what we expect it to be when the delegated function is called.Demo: http://jsfiddle.net/ambiguous/4c87J/
You can do delegation but you don't get it for free.
You cannot use an instance's .security object on the prototype. You need to create the isAuthenticated method in the constructor where you have access to it:
class Ctrl
constructor: (@security) ->
@isAuthenticated = security.isAuthenticated
…
(translate)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With