运算符优先级

您所在的位置:网站首页 matlab的运算优先级从高到低即指数运算 运算符优先级

运算符优先级

2024-07-11 19:02| 来源: 网络整理| 查看: 265

¥Precedence and associativity

考虑一个可以用下面的表示来描述的表达式,其中 OP1 和 OP2 都是运算符的填空项。

¥Consider an expression describable by the representation below, where both OP1 and OP2 are fill-in-the-blanks for OPerators.

a OP1 b OP2 c

上面的组合有两种可能的解释:

¥The combination above has two possible interpretations:

(a OP1 b) OP2 c a OP1 (b OP2 c)

语言决定采用哪一种取决于 OP1 和 OP2 的身份。

¥Which one the language decides to adopt depends on the identity of OP1 and OP2.

如果 OP1 和 OP2 具有不同的优先级(参见下表),则优先级较高的运算符先执行,并且结合性并不重要。观察乘法如何比加法具有更高的优先级并首先执行,即使加法首先写入代码中。

¥If OP1 and OP2 have different precedence levels (see the table below), the operator with the higher precedence goes first and associativity does not matter. Observe how multiplication has higher precedence than addition and executed first, even though addition is written first in the code.

jsconsole.log(3 + 10 * 2); // 23 console.log(3 + (10 * 2)); // 23, because parentheses here are superfluous console.log((3 + 10) * 2); // 26, because the parentheses change the order

在相同优先级的运算符中,语言按结合性对它们进行分组。左关联性(从左到右)意味着它被解释为 (a OP1 b) OP2 c,而右关联性(从右到左)意味着它被解释为 a OP1 (b OP2 c)。赋值运算符是右结合的,所以你可以写:

¥Within operators of the same precedence, the language groups them by associativity. Left-associativity (left-to-right) means that it is interpreted as (a OP1 b) OP2 c, while right-associativity (right-to-left) means it is interpreted as a OP1 (b OP2 c). Assignment operators are right-associative, so you can write:

jsa = b = 5; // same as writing a = (b = 5);

预期结果是 a 和 b 的值为 5。这是因为赋值运算符返回所分配的值。首先,b 设置为 5。然后 a 也被设置为 5 - b = 5 的返回值,也就是赋值的右操作数。

¥with the expected result that a and b get the value 5. This is because the assignment operator returns the value that is assigned. First, b is set to 5. Then the a is also set to 5 — the return value of b = 5, a.k.a. right operand of the assignment.

作为另一个例子,唯一的幂运算符具有右结合性,而其他算术运算符具有左结合性。

¥As another example, the unique exponentiation operator has right-associativity, whereas other arithmetic operators have left-associativity.

jsconst a = 4 ** 3 ** 2; // Same as 4 ** (3 ** 2); evaluates to 262144 const b = 4 / 3 / 2; // Same as (4 / 3) / 2; evaluates to 0.6666...

运算符首先按优先级分组,然后,对于具有相同优先级的相邻运算符,按关联性分组。因此,当混合除法和求幂时,求幂总是在除法之前。例如,2 ** 3 / 3 ** 2 结果为 0.8888888888888888,因为它与 (2 ** 3) / (3 ** 2) 相同。

¥Operators are first grouped by precedence, and then, for adjacent operators that have the same precedence, by associativity. So, when mixing division and exponentiation, the exponentiation always comes before the division. For example, 2 ** 3 / 3 ** 2 results in 0.8888888888888888 because it is the same as (2 ** 3) / (3 ** 2).

对于前缀一元运算符,假设我们有以下模式:

¥For prefix unary operators, suppose we have the following pattern:

OP1 a OP2 b

其中 OP1 是前缀一元运算符,OP2 是二元运算符。如果 OP1 的优先级高于 OP2,则将其分组为 (OP1 a) OP2 b;否则就是 OP1 (a OP2 b)。

¥where OP1 is a prefix unary operator and OP2 is a binary operator. If OP1 has higher precedence than OP2, then it would be grouped as (OP1 a) OP2 b; otherwise, it would be OP1 (a OP2 b).

jsconst a = 1; const b = 2; typeof a + b; // Equivalent to (typeof a) + b; result is "number2"

如果一元运算符位于第二个操作数上:

¥If the unary operator is on the second operand:

a OP2 OP1 b

那么二元运算符 OP2 的优先级必须低于一元运算符 OP1,才能将其分组为 a OP2 (OP1 b)。例如,以下内容无效:

¥Then the binary operator OP2 must have lower precedence than the unary operator OP1 for it to be grouped as a OP2 (OP1 b). For example, the following is invalid:

jsfunction* foo() { a + yield 1; }

因为 + 的优先级高于 yield,所以这将变成 (a + yield) 1,但因为 yield 在生成器函数中是 保留字,所以这将是一个语法错误。幸运的是,大多数一元运算符的优先级高于二元运算符,并且不会遇到此陷阱。

¥Because + has higher precedence than yield, this would become (a + yield) 1 — but because yield is a reserved word in generator functions, this would be a syntax error. Luckily, most unary operators have higher precedence than binary operators and do not suffer from this pitfall.

如果我们有两个前缀一元运算符:

¥If we have two prefix unary operators:

OP1 OP2 a

然后,更接近操作数 OP2 的一元运算符的优先级必须高于 OP1,才能将其分组为 OP1 (OP2 a)。也可以用另一种方式得到它并最终得到 (OP1 OP2) a:

¥Then the unary operator closer to the operand, OP2, must have higher precedence than OP1 for it to be grouped as OP1 (OP2 a). It's possible to get it the other way and end up with (OP1 OP2) a:

jsasync function* foo() { await yield 1; }

因为 await 的优先级高于 yield,所以这将变成 (await yield) 1,它正在等待名为 yield 的标识符,并且出现语法错误。同样,如果你有 new !A;,因为 ! 的优先级低于 new,所以这将变成 (new !) A,这显然是无效的。(无论如何,这段代码看起来毫无意义,因为 !A 总是生成一个布尔值,而不是构造函数。)

¥Because await has higher precedence than yield, this would become (await yield) 1, which is awaiting an identifier called yield, and a syntax error. Similarly, if you have new !A;, because ! has lower precedence than new, this would become (new !) A, which is obviously invalid. (This code looks nonsensical to write anyway, since !A always produces a boolean, not a constructor function.)

对于后缀一元运算符(即 ++ 和 --),适用相同的规则。幸运的是,这两个运算符的优先级都高于任何二元运算符,因此分组始终符合你的预期。此外,由于 ++ 求值为一个值,而不是一个引用,因此你也不能像在 C 中那样将多个增量链接在一起。

¥For postfix unary operators (namely, ++ and --), the same rules apply. Luckily, both operators have higher precedence than any binary operator, so the grouping is always what you would expect. Moreover, because ++ evaluates to a value, not a reference, you can't chain multiple increments together either, as you may do in C.

jslet a = 1; a++++; // SyntaxError: Invalid left-hand side in postfix operation.

运算符优先级将被递归处理。例如,考虑这个表达式:

¥Operator precedence will be handled recursively. For example, consider this expression:

js1 + 2 ** 3 * 4 / 5 >> 6

首先,我们通过降低优先级来对具有不同优先级的运算符进行分组。

¥First, we group operators with different precedence by decreasing levels of precedence.

** 运算符具有最高优先级,因此它首先分组。 环视 ** 表达式,右侧有 *,左侧有 +。* 具有更高的优先级,因此它被排在最前面。* 和 / 具有相同的优先级,因此我们现在将它们组合在一起。 环视分组为 2 的 *// 表达式,由于 + 的优先级高于 >>,所以将前者分组。 js (1 + ( (2 ** 3) * 4 / 5) ) >> 6 // │ │ └─ 1. ─┘ │ │ // │ └────── 2. ───────┘ │ // └────────── 3. ──────────┘

在 *// 组中,因为它们都是左结合的,所以左操作数将被分组。

¥Within the *// group, because they are both left-associative, the left operand would be grouped.

js (1 + ( ( (2 ** 3) * 4 ) / 5) ) >> 6 // │ │ │ └─ 1. ─┘ │ │ │ // │ └─│─────── 2. ───│────┘ │ // └──────│───── 3. ─────│──────┘ // └───── 4. ─────┘

请注意,运算符优先级和结合性仅影响运算符的求值顺序(隐式分组),而不影响操作数的求值顺序。操作数始终从左到右计算。优先级较高的表达式总是首先被求值,然后根据运算符优先级的顺序组合它们的结果。

¥Note that operator precedence and associativity only affect the order of evaluation of operators (the implicit grouping), but not the order of evaluation of operands. The operands are always evaluated from left-to-right. The higher-precedence expressions are always evaluated first, and their results are then composed according to the order of operator precedence.

jsfunction echo(name, num) { console.log(`Evaluating the ${name} side`); return num; } // Exponentiation operator (**) is right-associative, // but all call expressions (echo()), which have higher precedence, // will be evaluated before ** does console.log(echo("left", 4) ** echo("middle", 3) ** echo("right", 2)); // Evaluating the left side // Evaluating the middle side // Evaluating the right side // 262144 // Exponentiation operator (**) has higher precedence than division (/), // but evaluation always starts with the left operand console.log(echo("left", 4) / echo("middle", 3) ** echo("right", 2)); // Evaluating the left side // Evaluating the middle side // Evaluating the right side // 0.4444444444444444

如果你熟悉二叉树,请将其视为 后序遍历。

¥If you are familiar with binary trees, think about it as a post-order traversal.

/ ┌────────┴────────┐ echo("left", 4) ** ┌────────┴────────┐ echo("middle", 3) echo("right", 2)

当所有运算符被正确分组后,二元运算符将形成一棵二叉树。评估从最外面的组开始 - 这是优先级最低的运算符(在本例中为 /)。首先计算该运算符的左操作数,该操作数可能由更高优先级的运算符组成(例如调用表达式 echo("left", 4))。计算完左操作数后,以相同的方式计算右操作数。因此,所有叶节点(echo() 调用)都将从左到右访问,而不管加入它们的运算符的优先级如何。

¥After all operators have been properly grouped, the binary operators would form a binary tree. Evaluation starts from the outermost group — which is the operator with the lowest precedence (/ in this case). The left operand of this operator is first evaluated, which may be composed of higher-precedence operators (such as a call expression echo("left", 4)). After the left operand has been evaluated, the right operand is evaluated in the same fashion. Therefore, all leaf nodes — the echo() calls — would be visited left-to-right, regardless of the precedence of operators joining them.



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3