我使用CoffeScript创建了一些Javascript对象。这些对象之一是实验对象:

class Experiment
  @clock
  @events

  constructor: (@params) ->
    @events = new EventsTable
    @clock = 0

  run: ->
    setInterval ->
      perform_routine
    , 1000

  perform_routine: ->
    events = @events.get(@clock)

    for event in events
      if event['action'] == 'start'
        console.log('an event starts.')
      else
        console.log('an event has been finished.')

    console.log(@clock)
    @clock++


每次用户单击某个按钮时,都必须创建一个实验。考虑到这一点,我实现了一个jQuery触发器:

  $ ->
    $('#start-simulation').click (event) ->
      event.preventDefault();

      params = {}

      $('#simulation-parameters').find('input').each ->
        params[$(this).attr('name')] = $(this).val();

      simulation = new Experiment params
      simulation.run();


问题是我总是收到Uncaught ReferenceError:未定义实验

由于进行了一些研究,我还尝试使用@定义类名称,但是这样做时,使用类内部的方法会出现很多错误。

考虑到我以正确的顺序导入了所有必要的文件(第一次实验,然后是带有jQuery函数的实验),这种行为对我来说似乎是完全不自然的,但这可能是由于我缺乏JavaScript经验。

您知道在jQuery中使用JS外部对象的正确方法是什么吗?

最佳答案

您有几个问题:


CoffeeScript将代码包装在SIF中,以防止范围爬行。这个:

class C


变成这样的东西:

(function() {
    var C = // the JavaScript definition of C ...
}).call(this);


SIF包装器可以防止CoffeeScript中的任何内容意外污染全局名称空间。在您的情况下,Experiment JavaScript变量隐藏在函数内部,因此在任何其他CoffeeScript文件中都不可见。

通常的浏览器解决方案是说class @Experiment使您的类成为全局对象的属性。更好的解决方案是手动命名事物。在发生其他任何事情之前,您想说:

window.app = { } # where "app" is some namespace unique to your application


然后您可以说class app.Experimentnew app.Experiment
class级别,@是类本身。这意味着:

class Experiment
  @clock
  @events


声明了两个类属性(Experiment.clockExperiment.events),但忽略了为其赋予一个值。这些属性不在原型中,而是在类函数本身上。您可能想说:

class Experiment
  clock: undefined
  events: undefined


如果您的目的是告诉外界Experiment实例具有clockevents属性。
在CoffeeScript中,说f不会调用函数f,它只是为您提供对f的引用,而无需费心将其存储在任何地方。要调用不带参数的函数,请说f()。另外,如果要调用方法,则需要提供接收器。就您而言,您的constructor应该更像这样:

constructor: (@params) ->
  @events = new EventsTable
  @clock = 0
  @create_cells()
  @create_calls()

您的run方法遭受与constructor相同的“缺少接收者并且缺少函数调用括号”的问题。另外,当setInterval调用其回调时,它不提供任何特定的@(又名this),因此您需要一个绑定函数:

run: -> setInterval (=> @perform_routine()), 1000
# or
run: -> setInterval @perform_routine.bind(@), 1000
# or:
perform_routine: => ...
run: -> setInterval @perform_routine, 1000


您可能也想将setInterval返回值存储在某个地方,这样您可以调用clearInterval停止它:

run: ->
  @interval = setInterval ...
stop: ->
  clearInterval(@interval) if(@interval)
  @interval = undefined



您的Experiment其余部分中可能也有类似的问题。

09-25 19:10