开发者

What's up with this JavaScript pattern?

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 ex开发者_如何学运维plain?


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.


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).


I'm the author of the screencast mentioned, and the source of the snippet. A few clarifications:

  • The context in which the snippet was mentioned was in an animated comparison of JavaScript and CoffeeScript syntax.
  • It was intentionally simplified so as to not add extra confusion in the context of the CoffeeScript concept being taught at that exact moment in the video (the video was not trying to teach JavaScript constructor or class syntax).
  • You can get the full JavaScript text of any CoffeeScript snippet by running it through the CoffeeScript compiler as shown in the screencast, or by running it on the official CoffeeScript website.

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. ;-)


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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜