如何减少这些JS代码的行,使其更短,更高效?

时间:2017-06-15 22:05:13

标签: javascript function for-loop

我是JavaScript的新手,因此我目前正在研究MDN的官方2D突破游戏教程并自行更改内容以更好地了解工作原理。作为我在教程第6步(称为“构建砖块”)中的更改的一部分,我编写了以下代码,它完全符合我的要求,但我觉得我可以在某种程度上缩短代码,并且我不知道怎么做。

function drawBricks(){
    for(c = 0; c < bricksColCount-3; c++) {
        for(r = 0; r < bricksRowCount-1; r++) {
            setRowsCol();
        }
    }

    for(c = 2; c < bricksColCount-2; c++) {
        for(r = 0; r < bricksRowCount-4; r++) {
            setRowsCol();
        }
    }

    for(c = 3; c < bricksColCount; c++) {
        for(r = 0; r < bricksRowCount; r++) {
            setRowsCol();
        }
    }
}

我在这段代码中引用的setRowsCol()函数是这样写的:

function setRowsCol() {
    bricks[c][r].x = bricksOffsetLeft + (c*(bricksWidth + bricksPadding));
    bricks[c][r].y = bricksOffsetTop + (r*(bricksHeight + bricksPadding));
    ctx.beginPath();
    ctx.rect(bricks[c][r].x, bricks[c][r].y, bricksWidth, bricksHeight);
    ctx.fillStyle = "#fff";
    ctx.fill();
    ctx.closePath();
}

是否有任何想法减少线条并缩短代码而不改变其工作方式?由于我是JavaScript的新手,我想确保我应用适当的技巧。谢谢你们。

3 个答案:

答案 0 :(得分:5)

代码行数与代码运行速度没有直接关系。某些操作比其他操作更昂贵。

在您的示例中,canvas操作是目前最昂贵的操作。您的目标应该是通过减少画布操作的数量来提高速度。

我看到您在循环中调用setRowsCol(),在setRowsCol()内执行beginPath()closePath()。因为只有在开始绘图后才需要执行beginPath(),而在完成绘图后才需要执行closePath(),所以最好采取循环函数中的那两行。此外,fillStyle只需设置一次,fill()只需执行一次。它们也可以从setRowsCol()函数中删除。你可以这样写:

function setRowsCol() {
    bricks[c][r].x = bricksOffsetLeft + (c*(bricksWidth + bricksPadding));
    bricks[c][r].y = bricksOffsetTop + (r*(bricksHeight + bricksPadding));
    ctx.rect(bricks[c][r].x, bricks[c][r].y, bricksWidth, bricksHeight);
}

function drawBricks(){
    for(c = 0; c < bricksColCount-3; c++) {
        for(r = 0; r < bricksRowCount-1; r++) {
            setRowsCol();
        }
    }

    for(c = 2; c < bricksColCount-2; c++) {
        for(r = 0; r < bricksRowCount-4; r++) {
            setRowsCol();
        }
    }

    for(c = 3; c < bricksColCount; c++) {
        for(r = 0; r < bricksRowCount; r++) {
            setRowsCol();
        }
    }

}

var ctx=c.getContext("2d");
ctx.beginPath();
ctx.fillStyle = "#fff";
drawBricks();
ctx.fill();
ctx.closePath();

代码可能更好(例如,不依赖于全局范围变量),但想法是你已经在循环代码之外移动了一些昂贵的画布操作。

答案 1 :(得分:1)

function drawBricks(){
    function loop(startCol,endColOffset,endRowOffset){
        for(c = startCol; c < bricksColCount+endColOffset; c++) {
            for(r = 0; r < bricksRowCount+endRowOffset; r++) {
                setRowsCol();
            }
        }
    }
    loop(0,-3,-1);
    loop(2,-2,-4);
    loop(3,0,0);
}

答案 2 :(得分:0)

您询问如何缩短代码并提高效率,但我认为您应该解决更重要的问题。

编写正确,可读的代码

列上的for循环仅在bricksColumnCount为5时有效。要了解原因,请尝试在bricksColumnCount等于10的情况下运行代码。您会注意到一些列被多次绘制。

作为第一步,我会忘记bricksColumnCount并明确使用五列:

function drawBricks() {
    // columns 0 and 1 each have (bricksRowCount-1) bricks
    for (c = 0; c < 2; c++) {
        for (r = 0; r < bricksRowCount-1; r++) {
            setRowsCol();
        }
    }

    // column 2 has (bricksRowCount-4) bricks
    for (c = 2; c < 3; c++) {
        for (r = 0; r < bricksRowCount-4; r++) {
            setRowsCol();
        }
    }

    // columns 3 and 4 each have bricksRowCount bricks
    for (c = 3; c < 5; c++) {
        for (r = 0; r < bricksRowCount; r++) {
            setRowsCol();
        }
    }
}

要概括代码以使其适用于任意列计数,您需要决定如何对列进行分区并将其写为涉及bricksColumnCount的公式。问题中的原始代码是朝这个方向迈出的一步,但并不是很正确。

首选函数参数为全局变量

函数setRowsCol的行为由调用代码需要设置的全局变量cr控制。这种编程风格非常脆弱。有以下一些原因,请参阅http://wiki.c2.com/?GlobalVariablesAreBad

另一种方法是使用函数参数。有关简介,请参阅MDN Guide to Functions

您已经了解了在函数调用期间如何将值传递给函数:

ctx.rect(bricks[c][r].x, bricks[c][r].y, bricksWidth, bricksHeight);

函数ctx.rect需要知道要绘制的矩形的位置和尺寸,并通过在函数调用的括号内写入它们来传入它们。

要声明setRowsCol有两个参数,请将声明更改为以下内容:

function setRowsCol(c, r) {
    // the body remains the same
}

setRowsCol中对drawBricks的来电需要更新,因此它们看起来像这样:

setRowsCol(c, r);

调用中值的顺序必须与函数声明中参数的顺序相匹配,但名称不需要匹配。实际上,任何表达式都可以在函数调用中使用:

setRowsCol(1, 4);

这会调用setRowsCol,在setRowsCol正文中,c的值为1,r的值为4.

通过这些更改,变量cr不再需要全局变量,因此您应该将它们声明为drawBricks中的局部变量:

function drawBricks() {
    var c;
    var r;

    // columns 0 and 1 each have (bricksRowCount-1) bricks
    for (c = 0; c < 2; c++) {
        for(r = 0; r < bricksRowCount-1; r++) {
            setRowsCol(c, r);
        }
    }

    // etc.
}

现阶段不要担心效率

如果您编写的程序运行时间超过三秒,并且您希望让它运行得更快,则需要提高效率。但就目前而言,优先级列表上的效率应该非常低。