JS中的计算顺序
Order of calculation in JS
我的大学 codeboot.org 构建的解释器提供了对表达式的逐步执行。结果,我能够看到程序是如何读取算术表达式的。这就是我开始混淆的地方。
例如这个表达式:10-5+(7+2)/3
我们总是说要计算括号中的表达式,结果这就是我期望的顺序
- 7+2=9, 9/3=3, 10-5=5, 5+3=8
然而,解释器执行的内容完全不同。
- 10-5=5, 7+2=9, 9/3=3, 5+3=8
虽然结果是一样的,但是为什么要先算10-5呢? “我们必须先计算括号中的内容”会发生什么?这让我真的很困惑
我想知道解释器总是从左到右并先计算它能计算出的值是否是正确的行为。而不是像我们期望的那样直接跳到 ()
“先做括号”在 JS 中不是规则。而且“从左到右”也不是真正的规则。例如。考虑 1 + 4 * 6
。严格 left-to-right 会导致
- 1+4 = 5, 5*6 = 30
这不是 JS 所做的。
相反,JS 将你的表达式解析成一个表达式树,然后从树的根部开始计算它。 (严格来说,构建树不需要JS实现实现,但是需要和构建树一样的结果。)
例如,您的示例表达式 10-5+(7+2)/3
将生成大致如下所示的树:
AdditiveExpression:
AdditiveExpression
AdditiveExpression
MultiplicativeExpression
... NumericLiteral 10
- -
MultiplicativeExpression
... NumericLiteral 5
+ +
MultiplicativeExpression
MultiplicativeExpression
... ParenthesizeExpression
( (
Expression
... AdditiveExpression 7+2
) )
MultiplicativeOperator /
ExponentiationExpression
... NumericLiteral 3
其中:
- 我使用缩进来表示嵌套;
- 当我省略了很多中间推导时,我使用了“...”;和
- 我懒得给出“7+2”的完整 sub-tree。
(我找不到让 codeboot.org 显示其解析树的方法。如果有某种方法,或者如果您使用其他工具来显示表达式的解析树,请注意它可能看起来与上面的不完全一样,但它应该足够相似以产生相同的行为。)
要计算表达式,它从根开始,一个 AdditiveExpression
的子节点是:
- 另一个
AdditiveExpression
(对于10-5
),
+
令牌,以及
- a
MultiplicativeExpression
(对于 (7+2)/3
)。
规则是
- (a) 评估左操作数,然后
- (b)求右,然后
- (c) 对结果进行加法。
这就是为什么 (a) 10-5 => 5
是您的解释器计算的第一件事。
接下来是 (b) 计算 (7+2)/3
的 MultiplicativeExpression。这里的规则是类似的,所以我们需要:
- (b1) 评估左操作数(
(7+2)
的 MultiplicativeExpression),然后
- (b2) 评估右操作数(
3
的 ExponentiationExpression),然后
- (b3) 执行 MultiplicativeOperator
/
. 指示的操作
所以 (b1) 7+2 => 9
是下一件事,
然后 (b2) 3 => 3
,
然后 (b3) 9/3 => 3
.
我们现在完成了步骤 (b),所以我们继续 (c) 5+3 => 8
。
这与您的解释器执行的一系列计算相匹配。
我的大学 codeboot.org 构建的解释器提供了对表达式的逐步执行。结果,我能够看到程序是如何读取算术表达式的。这就是我开始混淆的地方。
例如这个表达式:10-5+(7+2)/3
我们总是说要计算括号中的表达式,结果这就是我期望的顺序
- 7+2=9, 9/3=3, 10-5=5, 5+3=8
然而,解释器执行的内容完全不同。
- 10-5=5, 7+2=9, 9/3=3, 5+3=8
虽然结果是一样的,但是为什么要先算10-5呢? “我们必须先计算括号中的内容”会发生什么?这让我真的很困惑
我想知道解释器总是从左到右并先计算它能计算出的值是否是正确的行为。而不是像我们期望的那样直接跳到 ()
“先做括号”在 JS 中不是规则。而且“从左到右”也不是真正的规则。例如。考虑 1 + 4 * 6
。严格 left-to-right 会导致
- 1+4 = 5, 5*6 = 30
这不是 JS 所做的。
相反,JS 将你的表达式解析成一个表达式树,然后从树的根部开始计算它。 (严格来说,构建树不需要JS实现实现,但是需要和构建树一样的结果。)
例如,您的示例表达式 10-5+(7+2)/3
将生成大致如下所示的树:
AdditiveExpression:
AdditiveExpression
AdditiveExpression
MultiplicativeExpression
... NumericLiteral 10
- -
MultiplicativeExpression
... NumericLiteral 5
+ +
MultiplicativeExpression
MultiplicativeExpression
... ParenthesizeExpression
( (
Expression
... AdditiveExpression 7+2
) )
MultiplicativeOperator /
ExponentiationExpression
... NumericLiteral 3
其中:
- 我使用缩进来表示嵌套;
- 当我省略了很多中间推导时,我使用了“...”;和
- 我懒得给出“7+2”的完整 sub-tree。
(我找不到让 codeboot.org 显示其解析树的方法。如果有某种方法,或者如果您使用其他工具来显示表达式的解析树,请注意它可能看起来与上面的不完全一样,但它应该足够相似以产生相同的行为。)
要计算表达式,它从根开始,一个 AdditiveExpression
的子节点是:
- 另一个
AdditiveExpression
(对于10-5
), +
令牌,以及- a
MultiplicativeExpression
(对于(7+2)/3
)。
规则是
- (a) 评估左操作数,然后
- (b)求右,然后
- (c) 对结果进行加法。
这就是为什么 (a) 10-5 => 5
是您的解释器计算的第一件事。
接下来是 (b) 计算 (7+2)/3
的 MultiplicativeExpression。这里的规则是类似的,所以我们需要:
- (b1) 评估左操作数(
(7+2)
的 MultiplicativeExpression),然后 - (b2) 评估右操作数(
3
的 ExponentiationExpression),然后 - (b3) 执行 MultiplicativeOperator
/
. 指示的操作
所以 (b1) 7+2 => 9
是下一件事,
然后 (b2) 3 => 3
,
然后 (b3) 9/3 => 3
.
我们现在完成了步骤 (b),所以我们继续 (c) 5+3 => 8
。
这与您的解释器执行的一系列计算相匹配。