While learning coffeescript, I'm trying to create an instance of class A inside a method of class B, this is the code:
class #A
constructor: (#x) ->
show: ->
alert #x
class #B
constructor: (#y) ->
show: ->
a = new #A("eric")
alert a.x
alert #y
b = new #B("daniel")
b.show()
the error is TypeError: undefined is not a function.
Any help is appreciated.
Thanks
You have two problems:
# is just another way of saying this in CoffeeScript. That's all it means.
Classes are (more or less) just variables or properties like any other in CoffeeScript.
So when you say #A, you're just looking for the A property of this and your show is really saying:
a = new this.A("eric")
In that context, # will be an instance of B and Bs don't have A properties. Instead you should just say:
a = new A('eric')
Using # when defining a class:
class #A
#...
is just a way to make a class globally available. At the top level, # will (almost always) be window in a browser so you're really saying:
class window.A
#...
and window properties are globals. Keep in mind that each CoffeeScript file is wrapped in a function when it is converted to JavaScript:
Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.
So if you just said:
class A
then A would only be available to other code in that file. Saying:
class #A
makes A global.
If you're only working with one file then you don't need the #s on your classes:
class A
constructor: (#x) ->
show: ->
alert #x
class B
constructor: (#y) ->
show: ->
a = new A("eric")
alert a.x
alert #y
b = new B("daniel")
b.show()
Don't get in the habit of prefixing everything with #, only use it on classes when you need it and you know exactly what it will do. Even when you need it, there are better ways: use require.js to manage your dependencies, use an global application-specific object to manage scopes, ...
Related
I want to join (use) classe in Coffescript files, and i found some usefull ideas here (sry for not including all links), since none fitted my needs (at least not as i like) I tried to find an own solution, this will work fine, but is there something I have overseen?
following "base" and "base class" are not OO words, I just did not find better names
I have a base (class) file TechDraw
class TechDraw
constructor: ->
$(window).load () =>
... do somthing
wave_to_me: ->
say 'I wave' # say is a basic func, I always use for debugging (console.log)
#TechDraw = new TechDraw
this works fine
Now I want to expand/extend my class with "sub classes/modules" in other files; ie. I have a TechDrawLine, and a TechDrawCalc, ans so on
What I did, was building a coffee file for each of them like:
class TechDrawConnector
constructor: (p)->
#parent=p
wave: (msg) ->
say 'yes its me, the connector:',msg
`window.TechDrawConnector = function(p) { return new TechDrawConnector(p) };`
# the last instead of a simple new like
# #TechDrawConnector = new TechDrawConnector
and my base(ic) class/module I extendet like this:
class TechDraw
constructor: ->
$(window).load () =>
#Connector=window.TechDrawConnector(this)
#LineGuy=window.TechDrawLineGuy(this)
#Connector.wave('init')
Since I am a newbee in coffeescript (yes javascript also) my solution feels to simple ...
Have I overseen somthing? The Polution of the global namespace is not so bad I think
You cant create an "extension" that way.
If you define the same class in the same namespace a second time the first class will simply be overwritten and become in accessible. This will mostly be dependent on the order of loading of the compiled JavaScript files.
However you could either later add an method to the prototype of the class
#file a.coffee
class A
constructor: ->
#foo()
#file B.coffee
A::foo = -> #do something
However this is no good style and can certainly be very confusing some time and lead to brittle errors.
Better would be to use a form of dependency injection
#file a.coffee
class A
constructor: (#closure) ->
$(window).load () => #closure()
#file B.coffee
new A () ->
#Connector=window.TechDrawConnector(#)
#LineGuy=window.TechDrawLineGuy(#)
#Connector.wave('init')
Hi I'm new to Js and Coffeescript, here's a situation I feel difficult to refer the property of parent object which is App in the following example
App =
init: ->
this.foo = 'bar'
this.bindEvent()
bindEvent: ->
$('#test').click(this.show)
show: ->
alert this.foo
App.init()
I think the fat arrow may do the trick but once I've changed to show: =>, this in the context of show method refers to the window object, instead of App object that I want to
. Anybody can tell me how to do it right?
http://jsfiddle.net/kZpHX/
When you define your show function, # (AKA this) actually is window so
show: => console.log(#)
will bind show to window. The problem is that you're simply defining an object so there isn't anything to bind to: you aren't defining a class so this is window. You could refer to App explicitly like this:
App =
#...
show: -> alert(App.foo)
Demo: http://jsfiddle.net/ambiguous/3sRVh/
The this.foo in init will do the right thing because saying App.init() sets up the expected this.
You could also hook up the desired this manually:
bindEvent: ->
$('#test').click => #show()
# or
bindEvent: ->
_this = # # JavaScript style
$('#test').click -> _this.show()
Demos: http://jsfiddle.net/ambiguous/byL45/, http://jsfiddle.net/ambiguous/MT8fG/
Or you could create a class for your App instead:
class App
constructor: ->
#foo = 'bar'
#bindEvent()
bindEvent: ->
$('#test').click(#show)
show: =>
console.log(#foo)
new App
That way your show: => will behave the way you expect it to.
Demo: http://jsfiddle.net/ambiguous/byatH/
Rails 3.2.8. In converting some of my JS functions over to CoffeeScript, I have come across several questions that say declaring a function like so:
#foo = (bar) ->
puts foo in the global namespace. But it doesn't, because my function calls elsewhere in the application, especially ones that are in .js.erb files.
Here's what does work:
foo = (bar) ->
window.foo = foo
With that, all my calls in .js.erb files work fine.
What is the reason that the #foo = notation doesn't work as I am expecting it to? That would be a lot easier than having to remember to add an extra line to expose the function to the global namespace.
#foo translates to this.foo
foo translates to var foo
There is a big difference between the two of those.
For example:
bar = (baz) ->
#bar = 5
lemon = #bar + baz
#foo = (bar) ->
lemon
return #
Bar = new bar(12)
Translates to:
var Bar, bar;
bar = function(baz) {
var lemon;
this.bar = 5;
lemon = this.bar + baz;
this.foo = function(bar) {
return lemon;
};
return this;
};
Bar = new bar(12);
See fiddle demo of generated code: http://jsfiddle.net/maniator/rXWw2/
Here is a link showing you the CoffeeScript and it's generated code
I just wanted to add something that seems important to understanding why the initial
#foo = () -> "abc"
doesn't add to the global window object.
Coffeescript wraps - once compiled, it wraps all contents of every .coffee-file into a surrounding anonymous function that is immediately executed.
Thusly, and explicitely for that reason, the global namespace is not polluted, thereby implicitely protecting the dev from creating "evil" globals.
So, your foo becomes a member function of an anonymous wrapper function - how seriously useless gg ...
I guess what you want anyway is your global config object or something, to which you simply add your definitions --- you surely didn't mean to really create globals just for quick and easy access now, did you?? :)
I come from a C#/Java background which use a class based OO system and I don't get the JavaScript/CoffeeScript prototype OO system yet. I've written a CoffeeScript class below which allows me to display names for contacts according to a system-side preference. I can only get the class to work by making the joinNonEmpty(stringList, joinText) method belong to the prototype and calling it the way I would call a static method in Java/C# land.
Is there a way I can make this method call using this.joinNonEmpty(...)?
Can you shed some light on why I can reference the firstLastRender, lastFirstRender and firstOrNickThenLast methods in the constructor with this. but it doesn't work from those methods when calling the joinNonEmpty helper?
Does this have something to do with how I'm locating the appropriate method via the preference map?
prefs = displayNameFormat: "FirstOrNickThenLast"
class DisplayNameRenderer
constructor: ->
#prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
# Why does this method have to be static (a class method)?
#joinNonEmpty: (stringList, joinText) ->
nonEmptyStrings = []
for s in stringList
nonEmptyStrings.push(s) if s isnt null and s isnt ""
nonEmptyStrings.join(joinText)
firstLastRender: (contact) ->
# TypeError: Object expected.
joinNonEmpty([contact.firstName, contact.lastName], ' ')
lastFirstRender: (contact) ->
# TypeError: Object doesn't support this method or property
this.joinNonEmpty([contact.lastName, contact.firstName], ', ')
firstOrNickThenLast: (contact) ->
# Works correctly.
DisplayNameRenderer.joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
#prefToRenderMap[prefs.displayNameFormat](contact)
contact = firstName: "Jonathan", nickname: "Jonny", lastName: "Appleseed"
dnr = new DisplayNameRenderer()
# => "Jonny Appleseed"
console.log dnr.render(contact)
Thanks for taking the time to answer.
this (AKA #) is determined when the function is called (with exceptions as below). So when you do this:
#prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
You're storing unbound references to the three functions in the #prefToRenderMap instance variable and #prefToRenderMap is itself an object. Then you try to call the methods in your DisplayNameRenderer instance like this:
#prefToRenderMap[prefs.displayNameFormat](contact)
and everything falls apart because the methods are called in the wrong context and # isn't what they're expecting it to be. If prefs is 'FirstOrNickThenLast' then you're effectively doing this:
#prefToRenderMap.FirstOrNickThenLast(contact)
and # (AKA this) will be #prefToRenderMap inside the firstOrNickThenLast method. But, of course, #prefToRenderMap doesn't have any of the methods that you're trying to call so you get various errors.
One solution is to use the fat arrow (=>) to define the methods:
The fat arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot.
So you could have things like this:
joinNonEmpty: (stringList, joinText) ->
#...
firstLastRender: (contact) =>
#joinNonEmpty([contact.firstName, contact.lastName], ' ')
and everything will work out. Here's a stripped down demo that will also show you your this problem:
http://jsfiddle.net/ambiguous/RAPJw/1/
You could also avoid this problem by referring to the methods by their names. Given a method name in a string, m = 'some_method', you can call that method like this o[m]() in both JavaScript and CoffeeScript and the result will be the same as if you said o.some_method(). A better structure would look more like this:
class DisplayNameRenderer
constructor: ->
#prefToRenderMap =
FirstOrNickThenLast: 'firstOrNickThenLast'
joinNonEmpty: (stringList, joinText) ->
#...
firstOrNickThenLast: (contact) ->
#joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
#[#prefToRenderMap['FirstOrNickThenLast']](contact)
Note the change to the structure of #prefToRenderMap and how it is used in render. And a demo of this approach: http://jsfiddle.net/ambiguous/DFYwu/
As an aside, instead of saying ClassName.class_method() inside an instance method, you can use the constructor property instead: #constructor.class_method(). Also, you usually say #method() or #property rather than this.method() and this.property in CoffeeScript.
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