求零次方

5 javascript language-lawyer

正如我们所知,将任何非零数进行零次方得到1,因为n^0 = n^(a-a) = n^a / n^a = 1

我刚刚注意到 JavaScript 实现(Chrome、Firefox、Edge、Safari)会简化此类操作,忽略第一个操作数并返回1. 然而,这些实现并不仅仅忽略第一个数字操作数,它们完全忽略任何东西!

console.log("hello" ** 0);
console.log(false ** 0);
console.log({} ** 0);
console.log(NaN ** 0);
console.log(null ** 0);
console.log(Infinity ** 0);
Run Code Online (Sandbox Code Playgroud)

我的问题是:该行为是一种实现(意味着它可以随时更改),还是由 ECMA 某处描述?我搜索了 ECMA但没有找到任何内容

小智 2

如果指数为 0 ,求幂运算符不会忽略或短路基操作数。但是,指数是否等于 0 的检查在运算符的算法中发生得足够早,因此很难观察到边缘情况。要了解发生了什么,有必要查阅 ECMAScript 规范以了解**调用该运算符时会发生什么:

13.6 指数运算符

13.6.1 运行时语义:评估

求幂表达式 : 更新表达式 ** 求幂表达式

  1. 返回 ?EvaluateStringOrNumericBinaryExpression(UpdateExpression**ExponentiationExpression)。

抽象操作 EvaluateStringOrNumericBinaryExpression计算两个操作数并将它们传递给另一个抽象操作:

13.15.4 评估字符串或数字二进制表达式(左操作数、opText、右操作数)

  1. lref为leftOperand的计算结果。
  2. lval为 ? 获取值(lref)。
  3. rref为计算rightOperand的结果。
  4. rval为 ? 获取值(rref)。
  5. 返回 ?ApplyStringOrNumericBinaryOperator(lvalopTextrval)。

抽象操作ApplyStringOrNumericBinaryOperator采用二元运算符及其操作数,执行所需的类型强制并调用与该运算符关联的抽象操作:

13.15.3 应用字符串或数字二进制运算符(lval、opText、rval)

  1. 如果opText+,那么 [...]
  2. 注意:此时必须是数值运算。
  3. lnum为 ? ToNumeric( lval ).
  4. rnum为 ? ToNumeric( rval ).
  5. [...]
  6. [...]
  7. 操作为与下表中的opText和 Type( lnum )关联的抽象操作: [...]
  8. 返回操作(lnumrnum)。

此时,基操作数被转换为数字。"hello"{}成为NaNfalsenull成为0,数字仍然是数字,BigInt 仍然是 BigInt。最后,如果opText**且 Type( lnum ) 为 Number,则关联运算为 Number::exponentiate:

6.1.6.1.3 Number::exponentiate(底数,指数)

  1. 如果指数为 NaN,则返回 NaN。
  2. 如果指数为 +0 或指数为 -0,则返回 1

因此,似乎无论基操作数是什么,如果指数为 0,该**运算符总是返回 1。如果不是 ApplyStringOrNumericBinaryOperator 的步骤 3,它就会返回 1。如果参数的类型为 Symbol,ToNumeric 会抛出 TypeError:

> Symbol() ** 0
Uncaught TypeError: Cannot convert a Symbol value to a number
Run Code Online (Sandbox Code Playgroud)

这表明,计算某个值的零次方不会忽略基操作数。