【问题标题】:Does the order of the comparison conditions matter when using OR operators in an IF function?在 IF 函数中使用 OR 运算符时,比较条件的顺序是否重要?
【发布时间】:2020-09-18 04:48:08
【问题描述】:

我试图更好地理解 IF 语句中的条件。当我更改条件的顺序时,我收到未定义的 TypeError。

当订单更改为:

if (col === maze[row].length || row < 0 || col < 0 || row === maze.length) {
    return
}

在 IF 函数中使用 OR 运算符时,比较的顺序是否重要?当订单写法不同时,是什么导致了TypeError

工作代码库:

const maze = [
  [' ', ' ', ' ', '*', ' ', ' ', ' '],
  ['*', '*', ' ', '*', ' ', '*', ' '],
  [' ', ' ', ' ', ' ', ' ', ' ', ' '],
  [' ', '*', '*', '*', '*', '*', ' '],
  [' ', ' ', ' ', ' ', ' ', ' ', 'e'],
];

const solve = (maze, row = 0, col = 0, path = "") => {

  if (row < 0 || col < 0 || row === maze.length || col === maze[row].length) {
    return
  }

  // Base case
  if (maze[row][col] === "e") {
    return console.log(`Solved at (${row}, ${col})! Path to exit: ${path}`)

    // General case
  } else if (maze[row][col] === "*") {
    return
  }

  // Marker
  maze[row][col] = "*"

  // Right
  solve(maze, row, col + 1, path.concat("R"))

  // Down
  solve(maze, row + 1, col, path.concat("D"))

  // Left
  solve(maze, row, col - 1, path.concat("L"))

  // Up
  solve(maze, row - 1, col, path.concat("U"))

  // Remove marker
  maze[row][col] = " "
}

console.log(solve(maze));

【问题讨论】:

  • 是的,当然这很重要 - js 是从左到右评估的,|| 运算符会短路。
  • 感谢@Bergi 的回复。我读到了运算符优先级link。当订单以不同方式编写时,我仍在努力理解导致 TypeError 的原因。您对为什么会发生 TypeError 有任何想法吗?
  • 当第一个真值条件发生时,其余条件不被评估并返回真值。这就是为什么即使后面的条件之一无效(您正在尝试读取未定义的长度属性),您也不会收到类型错误。当你改变条件的顺序,并且错误导致的条件是第一个时,会抛出错误,因为无效的部分将被评估。

标签: javascript if-statement or-operator


【解决方案1】:

在 IF 语句中使用 OR 运算符时,比较的顺序是否重要?

是的,除了运算符优先级之外,还需要查看associativityshort-circuit evaluation|| 运算符具有 left-to-right 关联性,这意味着它将从左到右评估表达式。短路评估意味着一旦结果已知,进一步的逻辑条件将被忽略。

当订单写法不同时,导致 TypeError 的原因是什么?

看你的情况:

col === maze[row].length || row < 0 || col < 0 || row === maze.length

因为逻辑运算是从左到右计算的,所以要计算的第一个是col === maze[row].length。当row === maze.length 时,col === maze[row].length 的计算结果为col === undefined.length,这当然会产生错误。

要解决此问题,您需要在首先确认索引不会越界之后运行此条件。一个简单的方法是:

row < 0 || col < 0 || row === maze.length || col === maze[row].length

现在,如果前三个条件中的任何一个是 true,那么 JavaScript 不会费心评估其余的条件,因为它已经知道结果是 true。因此,它不再崩溃。

(请记住true || false === true,所以只要你看到true ||,你甚至不需要阅读表达式的其余部分就知道结果将是true。)


请注意,如果您使用的语言使用短路评估,那么您将不得不使用多个if 语句以正确的顺序运行您的条件:

if (row < 0 || col < 0 || row === maze.length) {
    return
}

if (col === maze[row].length) {
    return
}

我经常发现自己开始编写这样的代码时,我会仔细考虑检查需要发生的顺序,然后我将其简化为一个表达式。


希望有帮助!

【讨论】:

  • 感谢您的周到回答。你在联想性和短路评估中的想法和内容非常有见地。 if (row &lt; 0 || col &lt; 0 || row === maze.length) { if (col === maze[row].length) { return } } maze[row] 的条件应该是最后一个。
  • "|| 运算符具有从左到右的关联性,这意味着它将从左到右计算表达式。" - 不。关联性与评估顺序无关,它始终是从左到右的。
  • @Beri,所以基本上我们应该根据关联性和从左到右的最高优先级列出条件。
  • @Bergi,好点,我刚刚查了一下,我明白你的意思了。看起来我将“评估”与“将运算符应用于操作数”混为一谈。什么是正确的措辞方式,而不会使 OP 过于技术化?
  • @Sam 只是省略了“precedence”和“associativity”,只说运算符是从左到右和短路计算的。
【解决方案2】:

你需要记住两件事。

  1. Javascript 评估是从左到右。
  2. OR || 运算符短路。这意味着它第一次遇到一个真正的表达式时,它会“短路”,即绕过所有其他表达式并只返回一个 true。这是基本的布尔代数。

关于您对TypeError: Cannot read property 'length' of undefined 的疑问,maze[row]maze 中的任何一个都未定义。在运行您的 sn-p 时,事实证明 maze[row] 是这里的罪魁祸首。这可能是因为由于您执行了row-1,因此在您的代码行中可能会变为负数,从而导致 maze[row] 未定义。

如果你把订单转到

if (row < 0 || col < 0 || col === maze[row].length || row === maze.length) {
    return
  }

每当row &lt; 0 即负或运算短路所有其他表达式。因此,maze[row].length 永远不会被评估,也不会遇到未定义的行为。

【讨论】:

  • || 运算符在遇到true 表达式而不是false 表达式时会短路。 (而&amp;&amp;false 上短路。)如果row &gt;= maze.length 发生变化,交换col === maze[row].length || row === maze.length 也是一个好主意,以防止在maze 更改时再次崩溃。
  • This might be because since you do a row-1, in your code row might become negative causing maze[row] to be undefined. 这个具体的句子提供了很多亮点。谢谢!
  • @Sam 感谢您指出这个愚蠢的错误。我已经修好了。
猜你喜欢
  • 1970-01-01
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
相关资源
最近更新 更多