3

如何为使用 CoffeeScript 编写的类创建命名空间?

例如,我有树类AaBbCc。我希望它们插入到全局可安全命名空间 - MyClasses中,允许跨它们通信并在 jasmine-node 中使用它们。

class MyClasses.Aa
 @someProp: true

class MyClasses.Bb
 @someProp2: false

class MyClasses.Cc
 @doSomeStuff: -> MyClasses.Aa.someProp = false

我知道,我可以将它们注入一个文件并编译,但我想要一个类=一个文件。

请问我该怎么做?谢谢!

编辑:我试过这种方式,但我认为它不好,但它适用于浏览器和 jasmine-node

root = exports ? this
root.MyClasses = root.MyClasses ? {}

root.MyClasses.Aa = 

  class Aa
4

3 回答 3

2

使用 RequireJS。

在一个名为“my-classes.coffee”的文件中,定义命名空间。

define [], ->
  # You need this if you want it to work in multiple environments.
  # Otherwise just use `window` to work in the browser.
  root = exports ? this

  root.MyClasses = {}

您可以在另一个名为“aa.coffee”的文件中定义您的课程。

define ['my-classes'], (MyClasses) ->

  class MyClasses.Aa
    @someProp: true

另一个文件:

define ['my-classes'], (MyClasses) ->

  class MyClasses.Bb
    @someProp2: false

现在,当您需要时,它应该导出MyClasses包括MyClasses.Aa.

require ['my-classes', 'aa'], (MyClasses, _) ->
  console.log MyClasses.Aa.someProp

这样做的一个问题是,您不能只依赖require语句中的“my-classes”。如果你这样做,MyClasses.Aa将是未定义的。但是你也不能只依赖“aa”,因为“aa”除了添加到 MyClasses 之外不会导出任何东西。在上面的代码片段中,MyClasses.Bb是未定义的,因为我没有明确依赖它。这就是为什么许多人要么使用一个巨大的文件,要么复制重新导出命名空间的样板。

如果有人知道如何解决这个问题,请告诉我。

我个人觉得 RequireJS 使用起来很复杂,并且有很多不同的方法来设置它。我将它与 jasmine 一起使用的一种方法是使用蛋糕任务将我的 CoffeeScript 预编译为 JavaScript,然后拥有这样的规范文件。

requirejs = require('requirejs')
# Set the baseURL to your compiled JS dir.
requirejs.config { baseUrl: __dirname + '/../lib' }

requirejs ['my-classes', 'aa'], (MyClasses, _) ->

  describe "someProp", ->
    it "should be true", ->
      expect(MyClasses.Aa.someProp).toEqual true

这可能不是最好的方法,但我能够使用它在浏览器、Node 服务器和 jasmine-node 测试中运行模块。我还看到有些人使用自定义运行器来避免其规范文件中的样板。

如果您不想使用 RequireJS,您可能会发现这个问题很有帮助。它通过使用CoffeeScript 常见问题解答namespace中定义的函数来工作。

于 2012-11-27T19:46:46.363 回答
1

Coffescript wiki 中有一个建议的解决方案:

来自https://github.com/jashkenas/coffee-script/wiki/FAQ

# Code:
#
namespace = (target, name, block) ->
  [target, name, block] = [(if typeof exports isnt 'undefined' then exports else window), arguments...] if arguments.length < 3
  top    = target
  target = target[item] or= {} for item in name.split '.'
  block target, top

# Usage:
#
namespace 'Hello.World', (exports) ->
  # `exports` is where you attach namespace members
  exports.hi = -> console.log 'Hi World!'

namespace 'Say.Hello', (exports, top) ->
  # `top` is a reference to the main namespace
  exports.fn = -> top.Hello.World.hi()

Say.Hello.fn()  # prints 'Hi World!'
于 2013-08-22T10:54:42.160 回答
0

-b您可以使用删除安全包装器的标志编译您的 CoffeeScript 文件。或者用你已经拥有的东西将你的类暴露在全局范围内

一杯咖啡

root = exports ? window
MyClasses = root.MyClasses = root.MyClasses ? {}

class MyClasses.Aa
  @someProp: true

b.咖啡

# same header as a.coffee
class MyClasses.Bb
  @someProp2: false

咖啡

# same header as a.coffee
class MyClasses.Cc
  @doSomeStuffWith: (someClass)-> 
    # pass a class to the method instead of just 
    # modifying another class within the same scope
    someClass.someProp = false

重复其他课程。在第一行中,我发现window比 更明确this,第二行还允许您将类附加到MyClasses没有长序列的命名空间。

在浏览器中,您的类将位于全局对象内MyClasses

在 node.js 中,您可以像这样使用它们(恕我直言,这有点冗长):

var Aa = require("./a").MyClasses.Aa,
    Bb = require("./b").MyClasses.Bb,
    Cc = require("./c").MyClasses.Cc;

console.log(Aa.someProp)  // true
console.log(Bb.someProp2) // false

Cc.doSomeStuffWith(Aa)

console.log(Aa.someProp) // false

pd:我没有用node-jasmine检查过。

于 2012-11-27T01:50:13.820 回答