setInterval и ошибка прототипа - PullRequest
1 голос
/ 06 августа 2011

Я пытаюсь сделать эффект 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 ]

1 голос
/ 06 августа 2011

Пара вещей, вы не можете отправить параметры в функцию в 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 );
0 голосов
/ 06 августа 2011

обратный вызов 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 имеет значение предела цикла.
Правильный способ передачи переменных в функцию cabback для setTimeout/ setInterval выглядит примерно так:

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() );
...