[英]Why the behavior for declaring vs does not declare the variable in JavaScript for Loop is different?
编辑:将标题更改为更相关的问题。
我发现 JavaScript 存在错误。 如果您在没有变量声明的情况下设置变量let
或var
。 例如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;
}
}
let
和var
之间的区别在这里没有问题。 如果您使用var
,第二个仍然可以工作,尽管您必须小心不要在 function 中重新使用它而不重新初始化它 - 不是let
的问题,其中变量的范围仅限于for
-loop声明的地方。
但是 JS 中声明的变量和未声明的变量之间存在严重差异。 声明的变量仅限于定义它的 scope; let
和const
对于包含块是本地的,而var
对于包含块 function 是本地的。 一个未声明的变量在整个程序中都是全局的; 如果任何地方有任何变化,它会为您的n
发生变化。
因此,如果我们首先检查正确的第二个样本,我们将n
声明为for
循环的局部变量,尝试n
为1
的可能性,并且说,发现这是不可能的,所以转到2
,这也不是可能,但是当我们尝试3
时,我们发现它是可能的。 (我没有使用您的示例网格,只是在这里制作东西;无论您的数据如何,这个想法都应该是相同的。)所以现在我们递归地调用solve
并再次到达这个循环。 我们创建另一个作用域变量n
,使用它完成我们的工作我们完成了调用并返回到这个循环,我们的初始n
在 scope 中,在下一次迭代中,将其设置为4
。 我们继续我们的快乐方式。 (这里看起来还有其他工作要做,以使其成为一个完整的数独求解器;在快速分析中,您总是回溯并且从未实际报告已解决的网格;但这与变量声明/范围的讨论无关。)
现在我们尝试您的第一个样品。 我们没有声明n
,所以它被设置为一个全局变量。 我们尝试了n
为1
和2
的可能性,这是不可能的。 我们尝试3
,这是可能的,所以我们递归地调用solve
并再次到达这个循环。 我们将n
初始化为 1,并通过所有可能性将 go 初始化,在循环结束后以n
结束,这意味着n
为 10。我们从递归调用返回到我们的第一个循环,击中行grid[r][c] = 0
,然后我们点击for
循环的增量步骤n++
,并将n
的(全局,记住)值设置为11
。 由于n < 10
是false
,我们完成了我们的循环和 function。
当您登录n
时,您现在将获得11
,一路上跳过了大部分可能性。 (在您的数据中,您得到15
,这意味着您在退出之前会退出更多级别的递归;再次,我发明数据是为了显示问题的想法,而不是您的数据的详细信息。)
教训应该很简单:总是声明你的变量。 这些天来,没有真正的理由使用var
。 我的建议是尽可能多地使用const
,而不能使用时使用let
。 但这不是重要的部分。 重要的部分就是永远不要使用未声明的变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.