JavaScript AddEventListener中的变量范围

时间:2012-05-02 04:49:58

标签: javascript global-variables scope addeventlistener

对于上下文,我正在为omniture(adobe)sitecatalyst编写一个用于视频跟踪的插件。在我以sitecatalyst格式编写插件之前,我想确认它是否正常工作。我已经测试了相同的代码,但使用了jQuery,它可以正常处理变量/范围。但直接使用Javascript进行操作证明有点困难。我在这里:

var vsa = new Array();
var vp = new Array(); 
vsa = document.getElementsByTagName('video');
if(vsa.length>0){
for(var vvv=0;vvv<vsa.length;vvv++) {
    vsa[vvv].addEventListener('seeked',function () { if(vp[vsa[vvv].id]) { s.Media.play(vsa[vvv].id,vsa[vvv].currentTime); }},false);
    vsa[vvv].addEventListener('seeking',function () { if(vp[vsa[vvv].id]) { s.Media.play(vsa[vvv].id,vsa[vvv].currentTime); }},false);
    vsa[vvv].addEventListener('play',function () { 
        if(!vp[vsa[vvv].id]) { 
            vp[vsa[vvv].id] = true; 
            s.Media.open(vsa[vvv].id,vsa[vvv].duration,s.Media.playerName);
            s.Media.play(vsa[vvv].id,vsa[vvv].currentTime); 
        } else {
            s.Media.play(vsa[vvv].id,vsa[vvv].currentTime);
        }},false);
    vsa[vvv].addEventListener('pause',function () { if(vp[vsa[vvv].id]) { s.Media.stop(vsa[vvv].id,vsa[vvv].currentTime); }},false);
    vsa[vvv].addEventListener('ended',function () { vp[vsa[vvv].id] = false; s.Media.stop(vsa[vvv].id,vsa[vvv].currentTime); s.Media.close(vsa[vvv].id); },false);

    if (typeof vsa[vvv].error != 'undefined' && vsa[vvv].error) {
        var scvt_msg = 'Error Not Captured';
        if(typeof vsa[vvv].error.code != 'undefined') {
            switch (vsa[vvv].error.code) {
                case MEDIA_ERR_ABORTED:
                    scvt_msg = 'vsa[vvv]eo stopped before load.';
                    break;
                case MEDIA_ERR_NETWORK:
                    scvt_msg = 'Network error';
                    break;
                case MEDIA_ERR_DECODE:
                    scvt_msg = 'vsa[vvv]eo is broken';
                    break;  
                case MEDIA_ERR_SRC_NOT_SUPPORTED:
                    scvt_msg = 'Codec is unsupported by this browser';
                    break;
            }
        }
        s.tl(this,'o','video: ' + scvt_msg);
    }

}
}

加载时,没有错误(意味着eventlisteners正确附加)。当我按下视频播放时,我得到一个“vsa [vvv]未定义”。在以

开头的代码行上
if(!vp[vsa[vvv].id]) 

如何从事件监听器函数访问vsa,vp和s的“全局”变量?

谢谢!

1 个答案:

答案 0 :(得分:3)

可以访问变量。问题是你陷入了(非常常见的)闭包里面的循环陷阱。

基本上,所有事件侦听器都共享相同的vvv变量。当事件监听器运行时,vvv已遍历所有循环并设置为vsa.length,使vsa [vvv]未定义。 (通过向您的事件监听器添加console.log(vvv)调用来检查这一点)

通常的解决方法是在循环外的函数中创建事件侦听器,以使每个事件侦听器获得自己对视频标记变量的引用。

function addMyEvents(node){
    //the inner functions here get their own separate version of "node"
    // instead of sharing the vvv
    node.addEventListener('seeked',function () { if(vp[node.id]) { s.Media.play(node.id, node.currentTime); }},false);
    node.addEventListener('seeking',function () { if(vp[node.id]) { s.Media.play(node.id, node.currentTime); }},false);
    //...
}

for(var vvv=0;vvv<vsa.length;vvv++) {
    addMyEvents(vsa[vvv]);
}

顺便说一下,你不需要在开始时进行if(vsa.length)测试,因为如果长度为零,循环就不会运行......


要在将来避免此错误,请通过JSHint或JSLint等linter运行代码。如果在for循环中创建函数,它们会发出警告。