在coffeescript构造函数中调用时,jQuery无法将事件处理程序附加到对象

时间:2014-03-12 16:08:54

标签: javascript jquery constructor event-handling coffeescript

我正在使用jQuery在多个javascript对象之间分派事件。

我有一个Coffeescript类,它将自定义事件处理程序附加到其构造函数中的对象:

class Player 

  constructor: ->
    @queue = new MediaQueue() # custom queue class
    $(@queue).on 'purged', (event, purged) => 
      media.destroy() for media in purged
      @fillQueue()

我的问题是永远不会调用此处理程序。

此外,在Chrome控制台内部,当我尝试:

$._data(player.queue, 'events')

我得到undefined

奇怪的是,将该处理程序附加到构造函数之外的任何位置都可以。

仍在Chrome控制台中:

$(player.queue).on('purged', function(event, purged){ 
  console.log('purged',purged) 
});
player.queue.purge();

=> purged, > Array[2]

如果绑定逻辑在构造函数之后被调用,它甚至可以工作:

class Player 

  constructor: ->
    @queue = new MediaQueue() 

  bindQueue: ->
    $(@queue).on 'purged', (event, purged) => 
       media.destroy() for media in purged
       @fillQueue()

然后:

var player = new Player();
player.bindQueue()
player.queue.purge() # the handler gets called as it should

我怀疑是一个可变范围问题。为什么我不能在构造函数中附加这个处理程序?

更新

我找到了一个奇怪的解决方法。

以下是我如何实例化该播放器:

$(document).ready ->
  $('[data-somenamespace-player]').each ->
    # the player is actually bound to a container
    # I just shortened the constructor code for simplicity's sake
    @somenamespace_player = new Player(@) 

如果我尝试像这样绑定处理程序,它就不起作用:

$(document).ready ->
  $('[data-somenamespace-player]').each ->
    @somenamespacePlayer = new Player(@)
    $(@somenamespacePlayer.queue).on 'purged', (event, purged) =>
      media.destroy() for media in purged
      @somenamespacePlayer.fillQueue()

...但是当我使用超时时可以正常工作

$(document).ready ->
  $('[data-somenamespace-player]').each ->
    @somenamespacePlayer = new Player(@)
    setTimeout =>
                 $(@somenamespacePlayer.queue).on 'purged', (event, purged) =>
                   media.destroy() for media in purged
                   @somenamespacePlayer.fillQueue()
               ,
               5000

怎么会这样?它可能是我的Queue类相对的东西吗?

更新

我在调试器中注意到了一些奇怪的东西。我在构造函数中设置了一个断点,然后尝试了这个:

$(this)
=> []

我还在一个使用的第一个队列方法中设置了一个断点,同样的交易:

$(this)
=> []

然后,在恢复执行并等待一下之后:

$(player.queue)
=> [>MediaQueue]

此外,当在MediaQueue构造函数内部时,我注意到一个奇怪的行为(实际编译的js):

function MediaQueue() {
      var _this = this; // if I try $(this) in the console at this stage, i get
                        // a TypeError : cannot read property length of undefined

      this._medias = [];      // idem at this stage, just before assignment
      this._currentIndex = 0; // now $(this) => []
}

我怀疑发生的事情超出了我对javascript如何运作的理解......

1 个答案:

答案 0 :(得分:1)

所以看来我犯了一个愚蠢的错误......

因此:

class MediaQueue 

  Object.defineProperties @prototype,
                          length: -> @_medias.length

当队列为空时,jQuery无法将事件处理程序附加到MediaQueue个对象 (这解释了setTimeout解决方法)。

我不确切知道为什么,但首先创造这样的财产肯定不是很聪明......

edit:原因是$ .each将具有length属性的对象视为可迭代,并尝试在对象的每个属性上附加处理程序而不是对象本身...

总结一下:当你想用jQuery触发事件时,不要在对象上创建length属性。

编辑

似乎我并不是唯一一个咬住子弹 - jQuery Bug Tracker上的某人filed this as an issue,只是因为理由而不是bug而关闭 - 这是$ .each的预期行为