更有效的数字比较

时间:2010-06-02 16:00:50

标签: javascript jquery

我有一个数组,它是我正在研究的小型JS游戏的一部分,我需要检查(通常是合理的)数组中的每个元素都没有离开“舞台”或“游乐场”,所以我可以删除它们并保存脚本加载

我编写了下面的代码,并且想知道是否有人知道更快/更有效的方法来计算它。这是每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;
}

非常感谢您给出的任何建议!

4 个答案:

答案 0 :(得分: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执行一次。

    在下面的示例中,我已将此引用存储在我的Bot对象的element属性中,但您可以将其添加到您的机器人(即bots[i][3]

  4. 将代表机器人的DOM元素的位置存储(缓存)到机器人表示中,因此不必一直计算CSS位置。

  5. 另外,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);
    

答案 1 :(得分:1)

您正在使用parseInt。据我所知,按位OR 0比parseInt快。所以你可以写

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

代替。

此外,我不会每隔50毫秒使用jQuery函数来获取这些值,因为使用它们时总会有更多的开销($函数必须解析其参数等) 。只需使用本机JavaScript函数来优化这些行。此外,使用您的代码,必须多次检索标识为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--) {
    …
}

答案 2 :(得分:0)

在javascript中查看here for a great comparison不同的循环技术。

使用for ... in性能较差,不建议在阵列上使用。向后循环并仍使用for循环的替代方法是缓存长度,以便每次迭代时都不会查找它。像这样:

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

但是有很多不同的方法,如上面的链接所示,你可能想用你的实际应用程序测试几个,看看哪种方法最适合你的情况。

答案 3 :(得分:0)

使用offset()position(),具体取决于您是否需要相对于文档或父级的坐标。 position()最有可能更快,因为浏览器可以有效地找到相对于父级的偏移量。不需要解析CSS。您也不需要lefttop变量,因为您只使用过一次。它可能不具有可读性,但你需要提高效率:

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