这个JavaScript模式有什么用?

时间:2011-05-13 21:54:29

标签: javascript coffeescript

我看到了这种模式:

Money = (function() {
    function Money(rawString) {
        this.cents = this.parseCents(rawString);
    }
});

在此CoffeeScript screencast preview中。 (截屏视频的主页为here。)

现在,我不明白这种模式。有Money函数包含Money函数。那是什么意思?

有人可以解释一下吗?

7 个答案:

答案 0 :(得分:17)

正如引用的那样,除了可以从Money对象中删除外window符号之外没有任何意义(IE7及以下除外,但这是另一个故事),因为它是正常的(隐式)window的属性(与var或从函数声明派生的符号相对)。但即使这样,外部Money符号也会收到一个绝对无效的函数。它会被错误引用吗?

例如,这是一个相当标准的模式:

Money = (function() {
    var someCompletelyPrivateVariable;

    function doSomethingCompletelyPrivate() {
    }

    function Money(rawString) {
        this.cents = this.parseCents(rawString);
    }

    return Money;
})();

这是模块模式,它允许您拥有完全私有的变量和函数(两者都有图示),同时只有一个公共符号。但是我必须编辑一下才能创建它(最重要的编辑结尾是return Money;,并且在匿名函数之后添加()所以我们调用< / em>它而不仅仅是定义它。

答案 1 :(得分:15)

使用视频声称的CoffeeScript代码是正确的转换......

class Money
    constructor: (rawString) ->
        @cents = @parseCents rawString

... CoffeeScript将生成以下内容,与@ T.J基本相同。克劳德的回答:

var Money;
Money = (function() {
  function Money(rawString) {
    this.cents = this.parseCents(rawString);
  }
  return Money;
})();

我只是发布这个来展示CoffeeScript 实际上做了什么,而且视频并不代表现实。

如果您visit the site,则可以看到转化,然后点击“试用CoffeeScript”按钮。

“接受”这个答案。


修改

要添加一些使用范围的私有变量用法,您可以这样做:

class Money
    priv=0
    constructor: (rawString) ->
        @cents = @parseCents rawString
        @id = priv++

...呈现为:

var Money;
Money = (function() {
  var priv;
  priv = 0;
  function Money(rawString) {
    this.cents = this.parseCents(rawString);
    this.id = priv++;
  }
  return Money;
})();

顺便说一句,我对CoffeeScript一无所知。它的语法让我感到困惑,但也许只是因为我不习惯它。

我喜欢JavaScript的方式(特别是新的和未来的变化)。

答案 2 :(得分:4)

我是所提到的截屏视频的作者,以及该片段的来源。一些澄清:

  • 提到该代码段的上下文是对JavaScript和CoffeeScript语法的动画比较。
  • 这是故意简化的,以免在视频中的那个时刻教授CoffeeScript概念的背景中增加额外的混淆(视频不是试图教授JavaScript构造函数或类语法)。
  • 您可以通过在截屏视频中显示的CoffeeScript编译器运行任何CoffeeScript代码段,或者在官方CoffeeScript网站上运行它来获取任何CoffeeScript代码段的完整JavaScript文本。

我会在上面提到的视频和预览中添加说明。

否则,Stack Overflow上的其他解释是正确的。如果您正在构建JavaScript类,则应返回当前对象并调用上面显示的匿名函数。但这不是CoffeeScript的重点。 ; - )

答案 3 :(得分:2)

它看起来不是一个真实的例子,“外部”功能的分组操作符是没有意义的,正如TJ所说,它绝对没有任何作用。被称为构造函数,它将返回一个空对象。

@TJ - 报价是正确的,您需要观看大约40秒的视频。

答案 4 :(得分:2)

Money = (function() {
    var uid = 0;
    function Money(rawString) {
        this.cents = this.parseCents(rawString);
        this.uid = uid++;
    }
    return Money;
})();

这种模式的另一个用例是让局部变量就像静态绑定到函数一样。

这与模块模式略有不同,因为您将静态私有信息添加到函数中。而不是打包数据并返回一个在范围内有一些局部变量的对象。

实现这一目标的另一个选择是使用Money.uid,但这将是公开的。

答案 5 :(得分:1)

这里有三件事:

首先,正如其他回答者所指出的那样,在PeepCode截屏视频中给出并在问题中引用的代码有两个错误。有return,外部函数被调用。

其次,作为T.J.注意,这是一个模块模式。您可以在CoffeeScript class块中执行任意代码,并且变量遵循与其他函数相同的作用域规则。所以,例如,你可以写

class HashedPassword
  salt = Math.random()
  constructor: (password) ->
    @value = hash password, salt

在这种情况下,salt仅在HashedPassword类定义中可见。

最后,应该注意的是,这是CoffeeScript唯一使用“命名”函数的地方(那些用function foo()而不是foo = function()声明的函数)。命名函数非常适合堆栈跟踪等,但它们会导致IE(&lt; 9)和其他浏览器之间出现不一致,除非作用于这样的模块(参见CoffeeScript FAQ,标题为“是”有没有办法命名函数,用于反射和递归?“)。因此,class语法的二次使用是安全地声明命名函数。

我希望能回答你的问题,Šime。

答案 6 :(得分:0)

外部Money函数不带参数。内部Money函数通过闭包捕获rawString。这里的优点是您不会使用内部Money函数定义来污染全局命名空间。

编辑:我同意TJ的说法,现在的模式是无用的。它没有做任何事情,外部功能仅用于范围界定。在没有看到截屏作者的完整示例的情况下,很难分辨出他的目标。