javascript - 为什么 typeof 只是有时抛出 ReferenceError?

标签 javascript expression language-lawyer typeof referenceerror

在 Chrome 和 Firefox 中,

typeof foo

计算为 'undefined'

但是

typeof (function() { return foo; })()

抛出一个错误:

ReferenceError: foo is not defined

这破坏了我对表达式可替代性的看法!直到现在,我还不知道 foo(function() { 返回的条件foo; })() 不一样。

这是标准行为吗?如果是这样,引用 ECMAScript 标准的相关部分会很有帮助。


编辑:

另一个例子:

typeof (foo)
typeof (foo + 0)

我本以为 (foo)(foo + 0) 会抛出错误。

但是第一个没有错误;第二个是。

最佳答案

基本上,typeof运算符检查变量¹ 是否不可解析并返回 "undefined"。也就是说,typeof 在到达 GetValue 之前返回未声明变量的定义值。抛出未声明变量的算法¹。

引用 ECMAScript 5.1 § 11.4.3 The typeof Operator (强调):

11.4.3 The typeof Operator

The production UnaryExpression : typeof UnaryExpression is evaluated as follows:

  1. Let val be the result of evaluating UnaryExpression.
  2. If Type(val) is Reference, then

    2.1. If IsUnresolvableReference(val) is true, return "undefined".

    2.2 Let val be GetValue(val).

  3. Return a String determined by Type(val) according to Table 20.

另一方面,return statement -- 像大多数从标识符中读取值的运算符和语句一样 -- 将始终调用 GetValue这会引发无法解析的标识符(未声明的变量)。引用 ECMAScript 5.1 § 8.7.1 GetValue (V) (强调):

8.7.1 GetValue (V)

  1. If Type(V) is not Reference, return V.
  2. Let base be the result of calling GetBase(V).
  3. If IsUnresolvableReference(V), throw a ReferenceError exception.

现在,分析代码:

typeof (function() { return foo; })()

此代码将实例化一个函数对象,执行它,然后 typeof 将对函数的返回值进行操作(函数调用在 typeof 运算符上采用 precedence) .

因此,代码在评估 IIFE 的 return 语句时抛出,然后才能评估 typeof 操作。

一个类似但更简单的例子:

typeof (foo+1)

加法在 typeof 之前求值。这将在 Addition Operator 时抛出错误。在 typeof 发挥作用之前,在 foo 上调用 GetValue

现在:

typeof (foo)

不会像 grouping operator 那样抛出错误(括号)本身并不“评估”任何东西,它只是强制优先。更具体地说,分组运算符不调用 GetValue。在上面的示例中,它返回一个(无法解析的)Reference

annotated ES5.1 spec甚至添加了关于此的注释:

NOTE This algorithm does not apply GetValue to the result of evaluating Expression. The principal motivation for this is so that operators such as delete and typeof may be applied to parenthesised expressions.


N.B. 我写这个答案的重点是提供一个简单易懂的解释,将技术术语保持在最低限度,同时仍然足够清晰,并提供所需的 ECMAScript 标准引用,我希望对难以理解 typeof 运算符的开发人员来说是一个有用的资源。

¹ 使用术语“变量”是为了便于理解。更正确的术语是标识符,它可以被引入到 Lexical Environment 中。不仅通过变量声明,还通过函数声明、形参、调用函数(arguments)、with/catch block 、赋值属性到全局对象、letconst 语句 (ES6),可能还有一些其他方式。

关于javascript - 为什么 typeof 只是有时抛出 ReferenceError?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24150713/

相关文章:

javascript - 计算棋盘游戏领土 (GO) 背后的逻辑

javascript - Jasmine + coffeescript - Jasmine 跳过测试

javascript - 从对象的 jQuery 集合中获取可见性

regex - 正则表达式中 (?s) 的含义

Javascript表达式短缺: value?值:'100'

linq - 动态 LINQ : Comparing Nested Data With Parent Property

javascript - 表单提交时出现 JQuery RangeError

c - strftime 和非标准化日期/时间

c++ - is_nothrow_default_constructible 带有 noexcept(false) 默认构造函数

c++ - 类成员转换函数-id