2010-06-02 69 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];