我正在使用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如何运作的理解......
答案 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的预期行为强>