JavaScript 三元运算符的运算符优先级

我似乎无法理解这段代码的第一部分(+ =)与 三元运算符三元运算符的组合。

h.className += h.className ? ' error' : 'error'

我认为这个代码的工作方式如下:

h.className = h.className + h.className ? ' error' : 'error'

但这并不正确,因为这会在我的控制台中出现错误。

我应该如何正确地解释这段代码?

99432 次浏览

用途:

h.className = h.className + (h.className ? ' error' : 'error')

你想让操作员为 h.className工作。最好具体一点。

当然,h.className += ' error'不应该造成伤害,但那是另一回事。

另外,请注意,+优先于三元运算符: JavaScript 运算符优先级

The right-hand side of the = operator is evaluated left to right. So,

g.className = h.className + h.className ? ' error' : 'error';`

相当于

h.className = (h.className + h.className) ? ' error' : 'error';

相当于

h.className += h.className ? ' error' : 'error';

你必须把括号中的三元语句分开:

h.className = h.className + (h.className ? ' error' : 'error');

The += does what you want, but in the ternary statement at the right hand of it, it checks if h.className is falsey, which it would be if it was undefined. If it's truthy (i.e. if a class name is already specified), then error is added with a space (i.e. adding a 新的 class), otherwise it's added without the space.

代码可以按照你的建议重写,但是你需要指定 h.className用于真实性比较,而不是在三元运算符中使用它的实际值,所以确保你不要在做三元运算的同时纠结于值的串联:

h.className = h.className + (h.className ? ' error' : 'error');
if (h.className) {
h.className = h.className + ' error';
} else {
h.className = h.className + 'error';
}

应相当于:

h.className += h.className ? ' error' : 'error';

这样想:

<variable> = <expression> ? <true clause> : <false clause>

语句的执行方式基本上如下:

  1. <expression>的计算结果是真还是假?
  2. 如果 <expression>的计算结果为 true,则将 <true clause>的值赋给 <variable>,忽略 <false clause>,并执行下一条语句。
  3. If <expression> evaluates to false, then <true clause> is ignored and the value of <false clause> is assigned to <variable>.

使用这种语言和其他语言中的三元运算符需要意识到的重要一点是,无论 <expression>中的代码是什么,在求值时都应该产生一个布尔值结果: true 或 false。

在你的例子中,将我的解释中的“赋值”替换为“添加到”,或者对于你正在使用的任何速记算法,如果有的话,类似的替换。

我想选择 韦恩的解释:

<variable> = <expression> ? <true clause> : <false clause>

让我们同时考虑这两种情况:

案例1

h.className += h.className ? 'true' : 'false'
  • 赋值运算符工作正常,并且附加值
  • 当它第一次运行时,输出为 false
  • 输出: false-true ——这些值一直在附加

案例2:

h.className = h.className + h.className ? 'true' : 'false'
  • 结果与情况1不同
  • 当它第一次运行时,输出为 假的
  • 输出: false ——值不会一直追加

解释

在上面的代码中,情况1工作得很好

whereas

个案2,

h.className = h.className + h.className ? 'true' : 'false'

被执行为

 h.className = (h.className + h.className) ? 'true' : 'false'

h.className + h.className = > 被认为是三元运算符的表达式,因为三元运算符具有更高的优先级。所以,三元表达式的结果总是被赋值。

h.className = h.className + (h.className ? ' error' : 'error')

但是我对这些答案并不是100% 满意,因为它们看起来都不完整。因此,我们再次从第一原则开始:

用户的总体目标:

总结代码: “我希望在字符串中添加一个 error类名称,如果字符串中已经有类名称,则可以选择使用前导空格。”

最简单的办法

就像5年前的 Kobi pointed out一样,在类名中占有前导空间不会对任何已知的浏览器造成任何问题,因此最简单的正确解决方案实际上是:

h.className += ' error';

That should have been the 真正的答案 to the 真正的问题.


尽管如此,问的问题是..。

1. 为什么这样做有效?

h.className += h.className ? ' error' : 'error'

条件/三元运算符的工作方式类似于 如果语句,它将其 truefalse路径的结果分配给一个变量。

这段代码之所以有效,是因为它被简单地评估为:

if (h.className IS NOT null AND IS NOT undefined AND IS NOT '')
h.className += ' error'
else
h.className += 'error'

2. 为什么会断裂?

h.className = h.className + h.className ? ' error' : 'error'

问题指出“在我的控制台中出现[ n ]错误”,这可能会误导您去思考代码 不起作用。实际上,下面的代码没有运行 错误,但是如果字符串 was not为空,它只返回“ error”,如果字符串 曾经是为空,则返回“ error”,如果字符串 不符合要求为空,则返回“ error”。

该代码总是生成一个只包含 ' error''error'的字符串,因为它的计算结果是这个伪代码:

if ((h.className + h.className) IS NOT null AND IS NOT undefined AND IS NOT '')
h.className = ' error'
else
h.className = 'error'

原因是加法运算符(通常是 +)的“优先级”(6)高于条件运算符/三元运算符(15)。I know the numbers appear backwards

优先级 仅仅意味着语言中每种类型的运算符都按照特定的预定义顺序进行计算(而不仅仅是从左到右)。

参考资料: JavaScript 运算符优先级

如何改变评估顺序:

现在我们知道它为什么失败了,你需要知道如何让它工作。

Some other answers talk about 改变优先顺序, but 你不能. Precedence is hard-wired into the language. That is just a fixed set of rules... However, you can change the 评估次序评估次序...

我们工具箱中可以使用 改变评估顺序的工具是分组操作符(又名括号)。它通过确保括号中的表达式在括号外被计算 之前操作来实现这一点。他们只做这些,但也足够了。

括号的工作原理很简单,因为它们(分组操作符)具有 优先级高于所有其他运算符(“现在有一个级别0”)。

By simply adding brackets you 改变评估顺序 to ensure the conditional test is performed first, before the simple string concatenation:

h.className = h.className + (h.className ? ' error' : 'error')