首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么JavaScript中的逻辑运算符是左关联的?

为什么JavaScript中的逻辑运算符是左关联的?
EN

Stack Overflow用户
提问于 2013-12-15 06:27:38
回答 3查看 2.3K关注 0票数 24

逻辑和或运算符是JavaScript和三元条件算子中唯一的惰性运算符。使用以下规则对它们进行短路评估测试:

代码语言:javascript
复制
false && anything === false
true || anything === true

这与在Haskell中实现的方式相同:

代码语言:javascript
复制
(&&) :: Bool -> Bool -> Bool
False && _ = False
True  && x = x

(||) :: Bool -> Bool -> Bool
True  || _ = True
False || x = x

然而,根据MDN,JavaScript中的逻辑运算符是左关联的。。这违反了直觉。在我看来,他们应该是正确的联想。哈斯克尔做的是对的。Haskell中的逻辑运算符是正确关联的:

代码语言:javascript
复制
infixr 3 &&
infixr 2 ||

考虑Haskell中的以下表达式:

代码语言:javascript
复制
False && True && True && True

因为&&在Haskell中是正确的关联,所以上面的表达式相当于:

代码语言:javascript
复制
False && (True && (True && True))

因此,(True && (True && True))表达式的计算结果并不重要。由于有了第一个False,整个表达式在一个步骤中被简化为False

现在,考虑一下如果&&是关联的,会发生什么。这句话相当于:

代码语言:javascript
复制
((False && True) && True) && True

现在需要3次削减才能评估整个表达式:

代码语言:javascript
复制
((False && True) && True) && True
(False && True) && True
False && True
False

正如您所看到的,逻辑运算符正确关联更有意义。这就引出了我的实际问题:

为什么JavaScript中的逻辑运算符是左关联的?ECMAScript规范对此有什么看法?JavaScript中的逻辑运算符实际上是关联的吗?MDN文档是否有关于逻辑运算符的相联性的错误信息?

编辑:根据规格说明逻辑运算符是左关联的:

代码语言:javascript
复制
LogicalANDExpression = BitwiseORExpression
                     | LogicalANDExpression && BitwiseORExpression

LogicalORExpression = LogicalANDExpression
                    | LogicalORExpression || LogicalANDExpression
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-12-17 18:54:21

对于任何优秀的编译器,这些操作符的选择相关性几乎都是无关的,并且输出的代码将是相同的。是的,解析树是不同的,但是发出的代码不需要。

在我所知道的C族的所有语言中( Javascript也属于这些语言),逻辑运算符都是相联的。所以真正的问题是,为什么类C语言将逻辑运算符定义为左联想呢?由于所选择的结合性是不相关的(就语义和效率而言),我怀疑最“自然的”(如“大多数其他运算符所使用的东西”)是选择了结合性,尽管我没有任何来源来支持我的说法。其他可能的解释是,左关联运算符使用LALR解析器解析时占用较少的堆栈空间(这现在不是什么大问题,但可能在C出现时就回来了)。

票数 15
EN

Stack Overflow用户

发布于 2013-12-24 04:04:04

考虑以下代码:

代码语言:javascript
复制
console.log(   true || (false && true) );   // right associative (implicit)
console.log(  (true || false) && true  );   // left associative (Javascript)

这两个例子实际上都返回相同的结果,但这并不是担心运算符结合性的原因。之所以与此相关,是因为逻辑运算符决定其结果的独特方式。即使所有排列最终得出相同的最终结论,计算的顺序也会发生变化,这可能对代码有很大的影响。

所以,现在考虑一下:

代码语言:javascript
复制
    var name = "";

    // ----------------------------------------
    // Right associative
    // ----------------------------------------
    name = "albert einstein";
    console.log("RIGHT : %s : %s", true || (false && updateName()), name);

    // ----------------------------------------
    // Left Associative
    // ----------------------------------------
    name = "albert einstein";
    console.log("LEFT  : %s : %s", (true || false) && updateName(), name);

    function updateName() {
        name = "charles manson";
        return true;
    }

输出是:

代码语言:javascript
复制
    RIGHT : true : albert einstein
    LEFT  : true : charles manson

这两个表达式都返回true,但只有与左关联的版本才需要调用updateName()才能返回答案。正确的关联版本不同。它只计算(false && updateName())中的第一个参数,因为第二个参数不能将false更改为true

记住这两点:

  • 算子优先描述了不同的算子类型的复合表达式的嵌套顺序。
  • 运算符结合性描述了具有相同运算符优先级的复合表达式的嵌套顺序。

请注意,上述两点都不改变单个表达式的解释方式,只改变复合表达式的解释方式。结合性发生在更高的层次上。

运算符结合性以及运算符优先性对语言的行为有着巨大的影响。理解这些差异对于能够使用和快速掌握不同编程语言中的功能差异至关重要。对于你的问题,你一定会得到我的赞许,我希望这能澄清一些问题。保重。

票数 5
EN

Stack Overflow用户

发布于 2013-12-23 22:54:00

简单的答案是:假设var i= null;if (i == null \x\x i.getSomeValue()) .当没有关联时,将首先评估第二个测试,从而给出一个异常。

票数 -4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20591876

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档