繁体   English   中英

为什么声明 vs 不声明 JavaScript for Loop 中的变量的行为不同?

[英]Why the behavior for declaring vs does not declare the variable in JavaScript for Loop is different?

编辑:将标题更改为更相关的问题。

我发现 JavaScript 存在错误 如果您在没有变量声明的情况下设置变量letvar 例如for (n=1;n<10;n++)与变量声明for (let n=1;n<10;n++) 您可以在 function 之外调用n变量,但它违反了 for 循环条件n<10 output 为15

JavaScript for Loop 没有变量声明。 for (n=1;n<10;n++)

 grid = [ [5, 3, 0, 0, 7, 0, 0, 0, 0], [6, 0, 0, 1, 9, 5, 0, 0, 0], [0, 9, 8, 0, 0, 0, 0, 6, 0], [8, 0, 0, 0, 6, 0, 0, 0, 3], [4, 0, 0, 8, 0, 3, 0, 0, 1], [7, 0, 0, 0, 2, 0, 0, 0, 6], [0, 6, 0, 0, 0, 0, 2, 8, 0], [0, 0, 0, 4, 1, 9, 0, 0, 5], [0, 0, 0, 0, 8, 0, 0, 7, 9] ]; function possible(r, c, n) { /// check the row for (let i = 0; i < 9; i++) if (grid[r][i] == n) return false; /// check the column for (let i = 0; i < 9; i++) if (grid[i][c] == n) return false; /// check the 3x3 grid r0 = Math.floor(r / 3) * 3; c0 = Math.floor(c / 3) * 3; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (grid[r0 + i][c0 + j] == n) return false; } } /// all check passed return true; } function solve() { for (let r = 0; r < 9; r++) { for (let c = 0; c < 9; c++) { /// check grid with value of 0 if (grid[r][c] === 0) { /// check for possible solution for (n = 1; n < 10; n++) { if (possible(r, c, n)) { /// there is a possibility of the selected solution is a bad one. /// to solve this, use backtracking: try -> if it turns out the solution is a bad one, we go back to 0. grid[r][c] = n; /// recursion solve(); grid[r][c] = 0; } } /// if there is no solution, we have to return. return; } } } console.log(grid); prompt("More?") } solve(); console.log(n)

JavaScript for 循环,变量声明for (let n=1;n<10;n++)

 grid = [ [5, 3, 0, 0, 7, 0, 0, 0, 0], [6, 0, 0, 1, 9, 5, 0, 0, 0], [0, 9, 8, 0, 0, 0, 0, 6, 0], [8, 0, 0, 0, 6, 0, 0, 0, 3], [4, 0, 0, 8, 0, 3, 0, 0, 1], [7, 0, 0, 0, 2, 0, 0, 0, 6], [0, 6, 0, 0, 0, 0, 2, 8, 0], [0, 0, 0, 4, 1, 9, 0, 0, 5], [0, 0, 0, 0, 8, 0, 0, 7, 9] ]; function possible(r, c, n) { /// check the row for (let i = 0; i < 9; i++) if (grid[r][i] == n) return false; /// check the column for (let i = 0; i < 9; i++) if (grid[i][c] == n) return false; /// check the 3x3 grid r0 = Math.floor(r / 3) * 3; c0 = Math.floor(c / 3) * 3; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (grid[r0 + i][c0 + j] == n) return false; } } /// all check passed return true; } function solve() { for (let r = 0; r < 9; r++) { for (let c = 0; c < 9; c++) { /// check grid with value of 0 if (grid[r][c] === 0) { /// check for possible solution for (let n = 1; n < 10; n++) { if (possible(r, c, n)) { /// there is a possibility of the selected solution is a bad one. /// to solve this, use backtracking: try -> if it turns out the solution is a bad one, we go back to 0. grid[r][c] = n; /// recursion solve(); grid[r][c] = 0; } } /// if there is no solution, we have to return. return; } } } console.log(grid); prompt("More?") } solve(); console.log(n)

为了更明确一点,在两个片段中的solve function 中,嵌套在两个for循环和一个if语句中,我们有这两个块中的任何一个——唯一的区别是第一个没有声明变量n和第二个:

        for (n = 1; n < 10; n++) {
          if (possible(r, c, n)) {
            grid[r][c] = n;
            solve();
            grid[r][c] = 0;
          }
        }
        for (let n = 1; n < 10; n++) {
          if (possible(r, c, n)) {
            grid[r][c] = n;
            solve();
            grid[r][c] = 0;
          }
        }

letvar之间的区别在这里没有问题。 如果您使用var ,第二个仍然可以工作,尽管您必须小心不要在 function 中重新使用它而不重新初始化它 - 不是let的问题,其中变量的范围仅限于for -loop声明的地方。

但是 JS 中声明的变量和未声明的变量之间存在严重差异。 声明的变量仅限于定义它的 scope; letconst对于包含块是本地的,而var对于包含块 function 是本地的。 一个未声明的变量在整个程序中都是全局的; 如果任何地方有任何变化,它会为您的n发生变化。

因此,如果我们首先检查正确的第二个样本,我们将n声明为for循环的局部变量,尝试n1的可能性,并且说,发现这是不可能的,所以转到2 ,这也不是可能,但是当我们尝试3时,我们发现它是可能的。 (我没有使用您的示例网格,只是在这里制作东西;无论您的数据如何,这个想法都应该是相同的。)所以现在我们递归地调用solve并再次到达这个循环。 我们创建另一个作用域变量n ,使用它完成我们的工作我们完成了调用并返回到这个循环,我们的初始n在 scope 中,在下一次迭代中,将其设置为4 我们继续我们的快乐方式。 (这里看起来还有其他工作要做,以使其成为一个完整的数独求解器;在快速分析中,您总是回溯并且从未实际报告已解决的网格;但这与变量声明/范围的讨论无关。)

现在我们尝试您的第一个样品。 我们没有声明n ,所以它被设置为一个全局变量。 我们尝试了n12的可能性,这是不可能的。 我们尝试3 ,这是可能的,所以我们递归地调用solve并再次到达这个循环。 我们将n初始化为 1,并通过所有可能性将 go 初始化,在循环结束后以n结束,这意味着n为 10。我们从递归调用返回到我们的第一个循环,击中行grid[r][c] = 0 ,然后我们点击for循环的增量步骤n++ ,并将n的(全局,记住)值设置为11 由于n < 10false ,我们完成了我们的循环和 function。

当您登录n时,您现在将获得11 ,一路上跳过了大部分可能性。 (在您的数据中,您得到15 ,这意味着您在退出之前会退出更多级别的递归;再次,我发明数据是为了显示问题的想法,而不是您的数据的详细信息。)

教训应该很简单:总是声明你的变量。 这些天来,没有真正的理由使用var 我的建议是尽可能多地使用const ,而不能使用时使用let 但这不是重要的部分。 重要的部分就是永远不要使用未声明的变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM