2010-06-02 43 views
3

我有一個數組,它是我正在研究的一個小JS遊戲的一部分,我需要檢查(經常合理)數組中的每個元素都沒有離開「stage」或「遊樂場」,所以我可以刪除它們並保存腳本加載更高效的數字比較

我編碼了下面,並想知道如果有人知道更快/更有效的方式來計算此。這是每50ms運行一次(它處理運動)。

其中bots[i][1]是X中的移動,而bots[i][2]是Y中的移動(互斥)。

for (var i in bots) { 
    var left = parseInt($("#" + i).css("left")); 
    var top = parseInt($("#" + i).css("top")); 
    var nextleft = left + bots[i][1]; 
    var nexttop = top + bots[i][2]; 
    if(bots[i][1]>0&&nextleft>=PLAYGROUND_WIDTH) { remove_bot(i); } 
    else if(bots[i][1]<0&&nextleft<=-GRID_SIZE) { remove_bot(i); } 
    else if(bots[i][2]>0&&nexttop>=PLAYGROUND_HEIGHT) { remove_bot(i); } 
    else if(bots[i][2]<0&&nexttop<=-GRID_SIZE) { remove_bot(i); } 
    else { 
     //alert(nextleft + ":" + nexttop); 
     $("#" + i).css("left", ""+(nextleft)+"px"); 
     $("#" + i).css("top", ""+(nexttop)+"px"); 
    } 
} 

在類似的註釋中,remove_bot(i);功能如下,這是正確的(我無法接合,因爲它改變了元素的所有的ID在數組中。

function remove_bot(i) { 
    $("#" + i).remove(); 
    bots[i] = false; 
} 

對於提出的任何建議非常感謝!

回答

8
  1. 緩存$("#" + i)在一個變量,每一次這樣做,正在創建一個新的jQuery對象

    var self = $('#' + i); 
    var left = parseInt(self.css("left")); 
    var top = parseInt(self.css("top")); 
    
  2. 緩存bots[i]在一個變量:

    var current = bots[i]; 
    var nextleft = left + current[1]; 
    var nexttop = top + current[2]; 
    
  3. 在bot表示中存儲(緩存)DOM元素的jQuery對象。目前它每隔50ms創建一次。

    我的意思是說,對於循環的每一次迭代,你都在做$('#' + i)。每次你調用這個時,jQuery都會構建一個DOM元素的jQuery對象。這是從遠古的相比JS的其他方面。 DOM遍歷/操作是目前爲止JavaScript最慢的部分。

    由於$('#' + i)的結果永遠不會改變每個機器人,爲什麼不把結果存儲在機器人?這樣$('#' + i)被執行一次,而不是每50ms。

    在我下面的例子中,我保存在我的機器人對象的element屬性此引用,但您可以添加它的機器人(在bots[i][3] IE)

  4. 存儲(高速緩存)的DOM的位置元素代表機器人表示中的bot,所以CSS位置不必一直計算。

請注意,for (.. in ..)應嚴格用於迭代對象而不是數組。數組應該被迭代使用for (..;..;..)

變量是極端在JavaScript中便宜;濫用它們。

這是我會選擇的實現,它結合了建議我做:

function Bot (x, y, movementX, movementY, playground) { 
    this.x = x; 
    this.y = y; 
    this.element = $('<div class="bot"/>').appendTo(playground); 
    this.movementX = movementX; 
    this.movementY = movementY; 
}; 

Bot.prototype.update = function() { 
    this.x += this.movementX, 
    this.y += this.movementY; 

    if (this.movementX > 0 && this.x >= PLAYGROUP_WIDTH || 
     this.movementX < 0 && this.x <= -GRID_SIZE || 
     this.movementY > 0 && this.y >= PLAYGROUND_HEIGHT || 
     this.movementY < 0 && this.y <= -GRIDSIZE) { 
     this.remove(); 
    } else { 
     this.element.css({ 
      left: this.x, 
      right: this.y 
     }); 
    }; 
}; 

Bot.prototype.remove = function() { 
    this.element.remove(); 
    // other stuff? 
}; 

var playground = $('#playground'); 
var bots = [new Bot(0, 0, 1, 1, playground), new Bot(0, 0, 5, -5, playground), new Bot(10, 10, 10, -10, playground)]; 

setInterval(function() { 
    var i = bots.length; 

    while (i--) { 
     bots[i].update(); 
    }; 
}, 50); 
+0

真的很有用的建議,我會盡快發佈更新的代碼。不過,我不明白3號你的意思是否可以進一步提醒?非常感謝, – 2010-06-02 16:35:09

+0

@PezCuckow:我已經擴展了我對#3的解釋 – Matt 2010-06-02 16:45:44

1

您使用parseInt。據我所知,按位OR 0比parseInt快。所以你可以寫

var left = $("#" + i).css("left") | 0; 

改爲。

此外,我不會利用jQuery函數每50毫秒獲取一次這樣的值,因爲在使用這些函數時($函數必須解析它的參數等)總是會有更多的開銷。只需使用原生JavaScript函數來優化這些行。此外,使用您的代碼,必須多次檢索ID爲i的元素。存儲這些元素在一個變量:

var item = document.getElementById(i); 
var iStyle = item.style; 
var left = iStyle.left; 
… 

(請注意,我不是一個jQuery的專家,所以我不是100%肯定這不會是相同的。)

此外,遞減while環路快於for循環(reference)。如果有通過以相反的順序元素循環沒有問題,你可以重寫你的代碼

var i = bots.length; 
while (i--) { 
    … 
} 
+0

重新使用while,我需要使用數組中元素的實際ID,因爲我刪除/刪除了一些它不能只是一個以遞增或遞減的值循環。 否則,奇妙的建議! – 2010-06-02 16:40:58

0

取在JavaScript不同循環技術一看here for a great comparison

使用for ... in性能較差,不建議在陣列上使用。另一種向後循環並仍然使用for循環的方法是緩存長度,以便每次迭代時都不要查找它。事情是這樣的:

for(var i, len = bots.length; i < len; i++) { ... } 

但也有許多不同的方法,如上面的鏈接,你可能想要測試一些與實際的應用程序,看看有什麼效果最好你的情況。

0

使用offset()position()取決於您是否需要相對於文檔或父級的座標。 position()最有可能更快,因爲瀏覽器可以高效地找到相對於父級的偏移量。沒有必要解析CSS。您也不需要lefttop變量,因爲您只使用它們一次。它可能不是可讀的,但你要提高效率:

var left = $("#" + i).position().left + bots[i][1]; 
var top = $("#" + i).position().top + bots[i][2];