Reputation: 185893
I saw this pattern:
Money = (function() {
function Money(rawString) {
this.cents = this.parseCents(rawString);
}
});
in this CoffeeScript screencast preview. (The homepage for the screencast is here.)
Now, I don't understand this pattern. There is a Money
function that contains a Money
function. What's that about?
Could someone explain?
Upvotes: 27
Views: 1198
Reputation: 71
I'm the author of the screencast mentioned, and the source of the snippet. A few clarifications:
I'll add a clarification to the video and preview mentioned above.
Otherwise, the other explanations here on Stack Overflow are correct. If you're building a JavaScript class you should return the current object and call the anonymous function shown above. But that's not the point of CoffeeScript. ;-)
Upvotes: 4
Reputation: 169383
Money = (function() {
var uid = 0;
function Money(rawString) {
this.cents = this.parseCents(rawString);
this.uid = uid++;
}
return Money;
})();
Another use case of this pattern is to have local variables that act as if there statically bound to the function.
This is subtly different from the module pattern because your adding static private information to a function. Instead of packaging data and returning an object which has some local variables in scope.
The other option for achieving this would be using Money.uid
but that would be public.
Upvotes: 2
Reputation: 77416
There are three things going on here:
First, as other answerers have noted, the code given in the PeepCode screencast and cited in the question has a couple of mistakes. There is a return
, and the outer function is called.
Second, as T.J. noted, this is a module pattern. You can execute arbitrary code in CoffeeScript class
blocks, and variables obey the same scoping rules as in other functions. So, for instance, you could write
class HashedPassword
salt = Math.random()
constructor: (password) ->
@value = hash password, salt
in which case salt
is visible only within the HashedPassword
class definition.
Finally, it should be noted that this is the only place that CoffeeScript ever uses "named" functions (those declared with function foo()
rather than foo = function()
). Named functions are great for stack traces and such, but they cause inconsistencies between IE (< 9) and other browsers unless scoped in a module like this (see the CoffeeScript FAQ, heading "Is there any way to name functions, for reflection and recursion?"). So a secondary use of the class
syntax is to safely declare named functions.
I hope that answers your question, Šime.
Upvotes: 1
Reputation: 11651
The outer Money function takes no arguments. The inner Money function captures rawString via closure. The advantage here is that you're not polluting the global namespace with the inner Money function definition.
EDIT: I would agree with TJ that the pattern as it stands is useless. It doesn't do anything and the outer function is used solely for scoping. Without seeing the screencast author's complete example, it's hard to tell where he is going with this.
Upvotes: 0
Reputation: 11327
Using the CoffeeScript code that the video claims is a proper conversion...
class Money
constructor: (rawString) ->
@cents = @parseCents rawString
...CoffeeScript will generate the following, which is basically identical to @T.J. Crowder's answer:
var Money;
Money = (function() {
function Money(rawString) {
this.cents = this.parseCents(rawString);
}
return Money;
})();
I'm just posting this to show what CoffeeScript actually does, and that the video does not represent the reality.
You can see the conversion if you visit the site and click the "Try CoffeeScript" button.
Please do not "accept" this answer.
EDIT:
To add some private variable usage that utilizes the scope, you could do this:
class Money
priv=0
constructor: (rawString) ->
@cents = @parseCents rawString
@id = priv++
...which renders as:
var Money;
Money = (function() {
var priv;
priv = 0;
function Money(rawString) {
this.cents = this.parseCents(rawString);
this.id = priv++;
}
return Money;
})();
By the way, I know nothing about CoffeeScript. Its syntax looks confusing to me, but perhaps just because I'm not accustomed to it.
I like JavaScript the way it is (especially with the new and yet to come changes).
Upvotes: 15
Reputation: 147363
It doesn't look like a real example, the grouping operator of the "outer" function is pointless and as TJ says, it does absolutely nothing. Called as a constructor, it will return an empty object.
@TJ - the quote is correct, you need to watch about 40 seconds of the video.
Upvotes: 2
Reputation: 1074088
As quoted, there's no point to that pattern other than that the outer Money
symbol can be deleted from the window
object (except on IE7 and below, but that's another story) because it's a normal (implicit) property of window
(as opposed to a var
or a symbol deriving from a function declaration). But even then, the outer Money
symbol receives a function that does absolutely nothing. Could it be misquoted?
For instance, here's a fairly standard patttern:
Money = (function() {
var someCompletelyPrivateVariable;
function doSomethingCompletelyPrivate() {
}
function Money(rawString) {
this.cents = this.parseCents(rawString);
}
return Money;
})();
That's the module pattern, and it lets you have completely private variables and functions (both illustrated) whilst only having one public symbol. But I've had to edit a fair bit to create that (the most significant edits being the return Money;
at the end and the addition of ()
after the anonymous function so we're calling it rather than just defining it.
Upvotes: 17