setInterval和原型错误

时间:2011-08-06 14:12:57

标签: javascript this setinterval prototype-programming

我正在尝试做一个shakeEffect,但是我收到了这个错误:

Uncaught TypeError: Cannot read property '1' of undefined
setTimeout.elementsCollection.style.position shake.js:66

第66行是:

this.elementsCollection[ i ].style.left = parseInt( Math.random() * 20 ) + 'px';

完整的代码:

Shake.prototype.shakeEffect = function(){
       if( this.elementsCollection.length != false ){
              var positions = this.shakePosition.split( '|' );
              for( var i = 0; i < this.elementsCollection.length; ++i ){
                     this.elementsCollection[ i ].style.position = 'relative';
                     this.effectInterval = setInterval( function( elementsCollection ) {
                            for( var x = 0; x < positions.length; ++x ){
                                   switch( positions[ x ] ){
                                          case 'left':
                                                 this.elementsCollection[ i ].style.left = -Math.abs( Math.random() * 20 ) + 'px';
                                                 break;
                                          case 'right':
                                                 this.elementsCollection[ i ].style.left = parseInt( Math.random() * 20 ) + 'px';
                                                 break;
                                          case 'top':
                                          case 'up':
                                                 this.elementsCollection[ i ].style.top = -Math.abs( Math.random() * 20 ) + 'px';
                                                 break;
                                          case 'down':
                                                 this.elementsCollection[ i ].style.top = parseInt( Math.random() * 20 ) + 'px';
                                                 break;
                                   }
                            }
                     } , this.getInterval() );
                     setTimeout( function(){
                            return function(){
                                   clearInterval( this.effectInterval );
                                   this.elementsCollection[ i ].style.position = null;
                            }
                     } , this.getTimeout() );
              }
       }
}

谢谢!

2 个答案:

答案 0 :(得分:1)

有些事情,你不能在setInterval中的函数中发送参数。你必须这样做:

setInterval(function (elementsCollection) { alert(elementsCollection) }, 1000 /*delay*/, array)

所以这应该有效:

this.effectInterval = setInterval( function( elementsCollection ) {
                        for( var x = 0; x < positions.length; ++x ){
                               switch( positions[ x ] ){
                                      case 'left':
                                             elementsCollection[ i ].style.left = -Math.abs( Math.random() * 20 ) + 'px';
                                             break;
                                      case 'right':
                                             elementsCollection[ i ].style.left = parseInt( Math.random() * 20 ) + 'px';
                                             break;
                                      case 'top':
                                      case 'up':
                                             elementsCollection[ i ].style.top = -Math.abs( Math.random() * 20 ) + 'px';
                                             break;
                                      case 'down':
                                             elementsCollection[ i ].style.top = parseInt( Math.random() * 20 ) + 'px';
                                             break;
                               }
                        }
                 } , this.getInterval(), this.elementsCollection );
                 setTimeout( function(elementsCollection){
                        return function(){
                               clearInterval( this.effectInterval );
                               elementsCollection[ i ].style.position = null;
                        }
                 } , this.getTimeout(), this.elementsCollection );

答案 1 :(得分:0)

setTimeout / setInterval回调是在与您的对象不同的上下文中执行的,当它被执行时,this关键字不会引用您的对象。
创建一个引用实例的变量,并在回调中使用它而不是this

// ... code
var self = this;
setTimeout( function(){
    return function(){
        clearInterval( self.effectInterval );
        self.elementsCollection[ i ].style.position = null;
    }
 } , this.getTimeout() );
 // ... code

执行this.effectInterval回调时,i值始终是循环的最后一个值。
试试自己:

for(var i=0;i<10;i++) 
    setTimeout(function(){console.log(i);},10);

结果与预期不符,因为函数在循环结束后执行,变量i具有循环限制值。
将变量传递给setTimeout / setInterval的cabback functin的正确方法如下:

function mySetTimeout(args,callback,time){
    return setTimeout(function(){
        callback.apply({},args);
    },time); 
};

然后您就可以使用它:

for(var i=0;i<10;i++) 
    mySetTimeout([i],function(i){console.log(i);},10);

因此,如果你使用特殊的mySetTimeout函数,当然还有类似的mySetInterval,那么你的有问题的代码可以按如下方式重写:

this.effectInterval = mySetInterval([i] function( i ) {
    for( var x = 0; x < positions.length; ++x ){
           switch( positions[ x ] ){
                  case 'left':
                         self.elementsCollection[ i ].style.left = -Math.abs( Math.random() * 20 ) + 'px';
                         break;
                  case 'right':
                         self.elementsCollection[ i ].style.left = parseInt( Math.random() * 20 ) + 'px';
                         break;
                  case 'top':
                  case 'up':
                         self.elementsCollection[ i ].style.top = -Math.abs( Math.random() * 20 ) + 'px';
                         break;
                  case 'down':
                         self.elementsCollection[ i ].style.top = parseInt( Math.random() * 20 ) + 'px';
                         break;
           }
    }
} , this.getInterval() );