【问题标题】:Operator precedence with Javascript Ternary operatorJavascript 三元运算符的运算符优先级
【发布时间】:2010-12-19 19:44:45
【问题描述】:

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

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

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

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

但这不正确,因为这会在我的控制台中显示错误。

所以我的问题是我应该如何正确地解释这段代码?

【问题讨论】:

    标签: javascript variable-assignment conditional-operator operator-precedence compound-assignment


    【解决方案1】:
    h.className = h.className + (h.className ? ' error' : 'error')
    

    您希望接线员为h.className 工作,最好具体说明一下。
    当然,h.className += ' error' 应该不会造成任何伤害,但那是另一回事。

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

    【讨论】:

    • 我认为应该注意的是,虽然h.className += ' error' 不会造成任何伤害,但如果它最初是空的,它也会在字符串的开头留下一个空格。我相信三元运算的重点是产生一个干净的字符串。
    • @JMTyler - 这正是我所表明的 - 如果这一切只是为了从一开始就保留一个空间,我不值得。 (边缘情况包括精确的 jQuery 或 XPath 选择器)。无论如何,谢谢。
    • @Kobi +1 仅用于运算符优先级警告!
    【解决方案2】:

    = 运算符的右侧从左到右计算。所以,

    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');
    

    【讨论】:

      【解决方案3】:

      += 做你想做的事,但在它右边的三元语句中,它检查h.className 是否为假,如果它未定义,它会是假的。如果它是真实的(即如果已经指定了类名),则在错误中添加空格(即添加 new 类),否则添加时不带空格。

      可以按照您的建议重写代码,但您需要在三元运算符中指定 h.className 用于真实性比较,而不是使用其实际值,因此请确保您不要在进行三元运算的同时还要处理值的串联:

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

      【讨论】:

      • 好吧,undefined 不是 false 它只是被当作是
      【解决方案4】:
      if (h.className) {
          h.className = h.className + ' error';
      } else {
          h.className = h.className + 'error';
      }
      

      应该相当于:

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

      【讨论】:

        【解决方案5】:

        这样想:

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

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

        1. &lt;expression&gt; 评估为真,还是评估为假?
        2. 如果&lt;expression&gt; 的计算结果为真,则将&lt;true clause&gt; 的值分配给&lt;variable&gt;,忽略&lt;false clause&gt;,并执行下一条语句。
        3. 如果 &lt;expression&gt; 的计算结果为 false,则忽略 &lt;true clause&gt;,并将 &lt;false clause&gt; 的值分配给 &lt;variable&gt;

        在这种语言和其他语言中使用三元运算符要实现的重要一点是,&lt;expression&gt; 中的任何代码在评估时都应该产生布尔结果:真或假。

        在您的示例中,将我的解释中的“分配给”替换为“添加到”,或者对于您使用的任何速记算术,如果有的话。

        【讨论】:

        • 请注意确定 perfect 评论是否合适 :) 它会跳过对 why 左侧表达式首先“组合在一起”的任何解释(即因为+ 比条件/三元运算符具有更高的优先级(事实上,条件运算符几乎总是在任何表达式中计算的最后一个)。
        【解决方案6】:

        我想选择韦恩的解释:

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

        让我们考虑这两种情况:

        case 1:
        h.className += h.className ? 'true' : 'false'     
        
        • 赋值运算符工作正常,值被附加
        • 第一次运行时,o/p: false
        • 第二次。 o/p: falsetrue -- 值不断追加

        案例2: h.className = h.className + h.className ? “真”:“假”

        • 结果与案例1不同
        • 第一次运行时,o/p: false
        • 第二次。 o/p: false -- 值不会一直附加

        explanation

        在上面的代码中,案例 1 工作正常

        而 案例2:

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

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

        需要用括号定义优先级

        您需要在括号的帮助下定义要考虑的评估顺序,以便案例 2 与案例 1 一样工作

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

        【讨论】:

        • 这里的术语不太对。优先级是语言固有的,您无需定义它。相反,您通过引入括号(其优先级高于所有其他运算符)来定义 求值顺序
        • @TrueBlueAussie 我接受。感谢您的阅读意图 +1
        【解决方案7】:

        我知道这是一个非常古老的问题,但我对任何答案都不是 100% 满意,因为它们似乎都不完整。因此,我们再次从第一任校长开始:

        用户的总体目标:

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

        最简单的解决方案

        正如 Kobi 指出的那样,5 年前,在类名中有一个前导空格不会对任何已知浏览器造成任何问题,因此最短的正确解决方案实际上是:

        h.className += ' error';
        

        这应该是实际问题实际答案


        尽管如此,提出的问题是......

        1) 为什么会这样?

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

        条件/三元运算符的工作方式类似于 if 语句,将其 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] 错误”,这可能会误导您认为代码不起作用。事实上,下面的代码确实会运行,但没有 error,但如果字符串 不是 为空,它只会返回“error”,如果字符串 was 为空,因此不符合要求

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

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

        原因是加法运算符(普通人的+)具有比条件/三元运算符(15)更高的“优先级”(6)。 我知道数字是倒数的

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

        参考:Javascript Operator Precedence

        如何更改评估顺序:

        现在我们知道它为什么会失败,您需要知道如何让它发挥作用。

        其他一些答案谈到改变优先级,但你不能。优先级是硬连线到语言中的。这只是一组固定的规则...但是,您可以更改评估顺序...

        我们工具箱中可以更改评估顺序的工具是分组运算符(又名括号)。它通过确保括号中的表达式在括号外的操作 before 进行评估来做到这一点。这就是他们所做的一切,但这已经足够了。

        括号之所以起作用,仅仅是因为它们(分组运算符)比所有其他运算符具有更高的优先级(“现在有一个级别 0”)。

        通过简单地添加括号,您更改评估顺序以确保先执行条件测试,然后再进行简单的字符串连接:

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

        我现在会把这个答案留给其他人看不到的 rust :)

        【讨论】:

          猜你喜欢
          • 2023-03-07
          • 1970-01-01
          • 2014-03-25
          • 2015-08-24
          • 2017-06-20
          • 2016-01-16
          • 2016-03-30
          • 1970-01-01
          • 2011-07-07
          相关资源
          最近更新 更多