【问题标题】:Using a local variable outside of its declaring scope; why does this work? [duplicate]在其声明范围之外使用局部变量;为什么这行得通? [复制]
【发布时间】:2014-06-04 18:17:26
【问题描述】:

我从一个网站上得到了这个游戏演示,并注意到了这段代码:

if(nx == food.x && ny == food.y) {
    var tail = {x: nx, y: ny};
    score++;
    create_food();
} else {
    var tail = snake_array.pop(); 
    tail.x = nx; tail.y = ny;
}

snake_array.unshift(tail); //how is tail used here?

我没有找到“tail”变量的任何其他声明,这是怎么回事?我对这个编程领域(网络开发/脚本语言)很陌生,所以我不确定这是否允许。

完整代码:

$(document).ready(function(){
    var canvas = $("#canvas")[0];
    var ctx = canvas.getContext("2d");
    var w = $("#canvas").width();
    var h = $("#canvas").height();

    var cw = 10;
    var d;
    var food;
    var score;

    var snake_array; 

    function init() {
        d = "right"; 
        create_snake();
        create_food(); 
        score = 0;

        if(typeof game_loop != "undefined") clearInterval(game_loop);
        game_loop = setInterval(paint, 60);
    }
    init();

    function create_snake() {
        var length = 5; 
        snake_array = []; 
        for(var i = length-1; i>=0; i--) {
            snake_array.push({x: i, y:0});
        }
    }

    function create_food() {
        food = {
            x: Math.round(Math.random()*(w-cw)/cw), 
            y: Math.round(Math.random()*(h-cw)/cw), 
        };
    }                

    function paint() {
        ctx.fillStyle = "white";
        ctx.fillRect(0, 0, w, h);
        ctx.strokeStyle = "black";
        ctx.strokeRect(0, 0, w, h);

        var nx = snake_array[0].x;
        var ny = snake_array[0].y;

if(d == "right") nx++;
        else if(d == "left") nx--;
        else if(d == "up") ny--;
        else if(d == "down") ny++;

        if(nx == -1 || nx == w/cw || ny == -1 || ny == h/cw || check_collision(nx, ny, snake_array)) {
            init();
            return;
        }

        /* @@@@@@@@@ This is where it is happening @@@@@@@@@ */
        if(nx == food.x && ny == food.y) {
            var tail = {x: nx, y: ny};
            score++;
            create_food();
        } else {
            var tail = snake_array.pop(); 
            tail.x = nx; tail.y = ny;
        }

        snake_array.unshift(tail);

        for(var i = 0; i < snake_array.length; i++) {
            var c = snake_array[i];
            paint_cell(c.x, c.y);
        }

        paint_cell(food.x, food.y);
        var score_text = "Score: " + score;
        ctx.fillText(score_text, 5, h-5);
    }

    function paint_cell(x, y) {
        ctx.fillStyle = "blue";
        ctx.fillRect(x*cw, y*cw, cw, cw);
        ctx.strokeStyle = "white";
        ctx.strokeRect(x*cw, y*cw, cw, cw);
    }

    function check_collision(x, y, array) {
        for(var i = 0; i < array.length; i++) {
            if(array[i].x == x && array[i].y == y)
             return true;
        }
        return false;
    }

    $(document).keydown(function(e) {
        var key = e.which;
        if(key == "37" && d != "right") d = "left";
        else if(key == "38" && d != "down") d = "up";
        else if(key == "39" && d != "left") d = "right";
        else if(key == "40" && d != "up") d = "down";
    })
})

代码来源:http://thecodeplayer.com/walkthrough/html5-game-tutorial-make-a-snake-game-using-html5-canvas-jquery

任何帮助将不胜感激:)

【问题讨论】:

  • tail 不是 if 本地的。
  • tailif 和正上方的else 中声明,因此无论哪种方式,它都在.unshift() 之前声明
  • 仅供参考,最好的写法是:var tail; if (...) { tail = {...}; } else { tail = {...}; }。将变量声明置于if 构造之外。像 JSLint 这样的东西实际上会抱怨你定义tail的方式,引用“可能使用未声明的变量'tail'”或“重复的变量声明'tail'”
  • @zamnuts 这实际上是我所期望的(使用未声明的变量)。让我失望的是它工作得很好。不过现在对我来说很有意义 :) 并感谢您的提醒!

标签: javascript jquery


【解决方案1】:

tail 是在 if 语句中声明的,因此它不受所述语句的范围限制。如果它在函数中,您将失去作用域。

正如 cmets 中所说,JavaScript 仅具有函数级作用域。

这是一个可以在控制台中运行的简单示例:

if (1>0) {
    var derp = "herp";
}
console.log(derp);
//outputs "herp"

【讨论】:

  • -1,循环不改变范围。
  • 这个答案的其他正确部分的措辞也很模糊 - 例如tail 没有在 if 语句中“声明”
  • @VinceEmigh JavaScript only 具有局部变量的函数级范围,var 声明语句(我喜欢将其视为“注释”)是 提升到封闭函数的顶部。也就是说,给定代码中只有一个tail 变量。
  • @RUJordan "Declared in" 意味着所有权和/或范围 - 在这种情况下,特别是考虑到 OP 的要求,这是一个模糊的答复。
  • @VinceEmigh 不客气!相关规范规则见10.5 Declaration Binding Instantiation(虽然有点罗嗦);这种效果的常用术语是“可变提升”。除了重复,参考。 stackoverflow.com/questions/21096904/…stackoverflow.com/questions/9085839/… (它们都在函数内的 var 声明语句之前显示局部变量的用法)
【解决方案2】:

var tailsnake_array.unshift(tail); 一样在 function paint() 中,因此它可以访问 var。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-06
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    相关资源
    最近更新 更多