【问题标题】:namespaces in coffeescript咖啡脚本中的命名空间
【发布时间】:2011-09-15 15:25:52
【问题描述】:

我想通过使用关键字“with”在 javascript 中使用命名空间,但 CoffeeScript 将此报告为保留关键字并拒绝编译有什么方法可以在 cs 中使用命名空间吗?

特别是,我想动态包含一个 CoffeeScript 文件(受信任的源),例如为数据库模式加载模型,但我希望包含的脚本能够访问本地命名空间。


编辑:

这就是我想要做的。我正在建立一个 web 框架,将目录树映射到基于 express 和 mongoose 的应用程序。例如,有一个子目录“models”,其中包含一个文件“user.coffee”,其中包含如下代码:

name:
    type: String
    unique: on
profiles: [ Profile ]

其中Profile 是一个位于名为model 的本地对象中的类。加载用户模型时,我希望它访问位于本地模型存储中的模型类。

我现在的解决方法是将model.Profile 写入文件'user.coffee'。希望我的意思很清楚。


第二次编辑

这是我在不使用 with 的情况下是如何做到的:

user.coffee

name:
    type: String
    unique: on
profiles: [ @profile ]

profile.coffee

content: String

它是如何动态加载的:

for fm in fs.readdirSync "#{base}/models"
    m = path.basename fm, '.coffee'
    schema[m] = (()->
        new Schema coffee.eval (
            fs.readFileSync "#{base}/models/#{fm}", 'utf8'
        ), bare: on
    ).call model
    mongoose.model m, schema[m]
    model[m] = mongoose.model m

对我来说似乎是一个不错的解决方案。

【问题讨论】:

  • 恐怕您的编辑并没有使您的意图更加清晰。您能否添加model.Profile 的代表代码以及您希望如何使用它?
  • 定义时在Profile前面加上@class @Profile。由于thisglobal,这将使它成为一个名为Profile 的全局变量。 user.coffee 无需更改(尽管您可以编写 @Profile 以更清楚地表明您正在引用全局)。
  • Profile 是一个猫鼬模式,它的动态定义方式与 User 相同:通过 CoffeeScript 文件。 profile.coffee 在这种情况下。请参阅 github.com/LearnBoost/mongoosemongoosejs.com - 所以我无法全局定义它。尽管如此,我还是想避免全局定义。不过,我会试试 @ - 它是 CoffeeScript 中 this 的同义词,对吧?
  • 好吧,如果@ 编译成this,我就不能在其他函数中使用它,比如回调,因为它会引用那个函数...
  • 顺便说一句,我现在考虑使用coffee.eval 不是一个好主意。相反,可以只使用 require 来解析 coffe-script 文件。

标签: javascript namespaces coffeescript


【解决方案1】:

别人的意见强加给你?现在是 Hack Time™!

o =
  a: 1
  b: 2
  c: 3

`with(o) {//`
  alert a
`}`

“编译”为:

var o;
o = {
  a: 1,
  b: 2,
  c: 3
};
with(o) {//;
alert(a);
};

很遗憾,这是 Doug Crockford 的观点被视为福音的另一个领域。 with Statement Considered Harmful 基于属性写入的模糊性拒绝它,但在与 只读 上下文对象(例如定义类似 DSL 的 API 的上下文对象)一起使用时忽略了它的用处。

【讨论】:

  • 不管怎样,这在 CS 和 ES5 严格模式下都是语法错误,因此应该由负责任的工程​​师避免。
  • 不过,不仅仅是 Crockford。正如lawnsea 指出的那样,with 在 ES5 严格模式下已被弃用和禁止。 (仅此一点就足以让 CoffeeScript 不编译它。)它还在大多数 JS 环境中产生巨大的性能影响(例如,尝试this benchmark)。
  • ES5 严格模式是opt-in,所以with 对于那些认为它在真正有用的特定场景中有用的人来说是无用的。
  • 这个答案是错误的。如果您从 google 不要这样做来到这里。如果coffee 决定以后在编译的JS 中包含"use strict"; 会发生什么?除非您别无选择,否则不要将 JS 内联到 CoffeeScript 中。在这种情况下,解构赋值或 Trevor 的答案就可以了。
  • 刚刚试了一下,效果很好。谢谢!但是,如果有没有with 的解决方案,我更喜欢那个......
【解决方案2】:

CoffeeScript 的 Coco 分支支持 with 语法;见https://github.com/satyr/coco/wiki/additions。但是,该语法只是将 this 的值设置为块中的目标对象,而不是编译为有问题且已弃用的 with 关键字。

假设您想在 CoffeeScript 中模拟 Coco 的 with 语法。你会做这样的事情:

withObj = (obj, func) -> func.call obj

那么你可以写

withObj = (obj, func) -> func.call obj
withObj annoyingly.lengthy.obj.reference, ->
  @foo = 'bar'
  @bar = 'baz'

当然,在这种简单的情况下,最好使用jQuery或者Underscore的extend这样的实用函数:

_.extend annoyingly.lengthy.obj.reference, foo: 'bar', bar: 'baz'

【讨论】:

  • 感谢您的提示。我使用了调用方法。忘记了。
【解决方案3】:

没有。但是,您可以使用destructuring assignment 来达到类似的效果。

{foo, bar, baz} = require 'toocoollib'
foo 'whoa!'

您还应该知道 with 关键字已被弃用,在 ES5 严格模式下是 syntax error。主流 JS 黑客的共识是with 是个坏主意。

如果您发布了您想做的示例,我可以给出更具体的答案。

【讨论】:

  • 顺便说一句,我使用的是node,直到现在它似乎都没有抱怨with。我已经指定了示例,并希望以某种方式清楚我想要实现的目标:-)
  • 解构赋值对我不起作用,因为我事先不知道名称。但是我发现了另一种可能性,使用匿名函数及其上的调用方法,传递我想要延迟的未知对象。
【解决方案4】:

刚刚在 CoffeeScript 常见问题页面上找到了关于“变量导入”的内容:

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

在 CoffeeScript 中似乎不鼓励使用这种技术,并且不支持。

【讨论】:

    猜你喜欢
    • 2011-11-02
    • 1970-01-01
    • 2012-02-25
    • 2012-10-13
    • 2012-07-17
    • 1970-01-01
    • 2013-01-09
    • 1970-01-01
    相关资源
    最近更新 更多