在Chrome和Firefox中,
typeof foo
评估为'undefined'
。
但是
typeof (function() { return foo; })()
抛出错误:
ReferenceError: foo is not defined
这破坏了我对表达式可疑性的概念!到目前为止,我知道foo
和(function() { return foo; })()
不相同的条件。
这是标准行为吗?如果是这样,引用ECMAScript标准的相关部分会很有帮助。
编辑:
另一个例子:
typeof (foo)
typeof (foo + 0)
我希望(foo)
和(foo + 0)
会抛出错误。
但第一个没有错误;第二个。
答案 0 :(得分:15)
基本上,typeof
运算符检查变量¹是否不可解析并返回"undefined"
。也就是说,typeof
在达到GetValue
算法之前返回未声明变量¹的定义值,该算法会抛出未声明的变量¹。
引用ECMAScript 5.1 § 11.4.3 The typeof Operator(强调补充):
11.4.3运营商类型
制作 UnaryExpression :
typeof
UnaryExpression 是 评估如下:
另一方面,return statement - 像大多数读取标识符值的运算符和语句一样 - 将始终调用GetValue
,它会抛出不可解析的标识符(未声明的变量)。引用ECMAScript 5.1 § 8.7.1 GetValue (V)(强调补充):
8.7.1 GetValue(V)
- 如果Type(V)不是参考,请返回V.
- 让base成为调用GetBase(V)的结果。
- 如果IsUnresolvableReference(V),则抛出
醇>ReferenceError
例外。
现在,分析代码:
typeof (function() { return foo; })()
此代码将实例化一个函数对象,执行它,然后typeof
将对函数的返回值进行操作(函数调用typeof
运算符上的precedence。)
因此,代码在评估IIFE return
语句时抛出,然后才能评估typeof
操作。
一个类似但更简单的例子:
typeof (foo+1)
在typeof
之前评估添加。在GetValue
开始播放foo
之前,typeof
调用typeof (foo)
时会出现错误。
现在:
GetValue
不抛出错误,因为Addition Operator(括号)本身没有“评估”任何东西,它只是强制优先。更具体地说,分组运算符不会调用delete
。在上面的示例中,它返回一个(不可解析的)参考。
grouping operator甚至添加了关于此的说明:
注意此算法不会将annotated ES5.1 spec应用于评估Expression的结果。这样做的主要动机是,
typeof
和typeof
等运算符可以应用于带括号的表达式。
NB 我写了这个答案的重点是提供一个简单易懂的解释,将技术术语保持在最低限度,同时仍然足够清晰,并提供所要求的ECMAScript标准参考,我希望成为那些努力理解arguments
运算符的开发人员的有用资源。
¹术语“变量”用于便于理解。更正确的术语是标识符,它不仅可以通过变量声明引入GetValue
,还可以引入函数声明,形式参数,调用函数(with
) ,catch
/ let
阻止,将属性分配给全局对象,const
和{{1}}语句(ES6),以及其他一些方法。
答案 1 :(得分:8)
这是标准行为吗?
是。 typeof 不会抛出错误,因为它只返回值as specified。但是,正如其他答案所述,代码在评估操作数时失败。
如果是这样,引用ECMAScript标准的相关部分会很有帮助。
在计算函数表达式时,尝试解析 foo 的值(以便可以返回它)将使用参数 foo调用内部GetValue方法。但是,由于 foo 尚未声明或以其他方式创建,因此引发了引用错误。
以下情况:
typeof (foo)
"("和")"是punctuators,表示分组,例如调用像foo(a, b)
这样的函数时的(可能是空的)参数列表,或表示要评估的表达式,例如if (x < 0)
等等。
在typeof (foo)
的情况下,他们只是在应用typeof运算符之前表示评估 foo 。因此,作为有效标识符的 foo 将传递给 typeof ,上面的每个链接尝试解析它,无法确定它是否为 无法解析的引用,并返回字符串"undefined"
。
以下情况:
typeof (foo + 0)
括号导致首先计算表达式foo + 0
。获取 foo 的值时,会引发引用错误,因此 typeof 无法运行。请注意,没有括号:
typeof foo + 0 // undefined0
由于运算符优先级:typeof foo
返回字符串"undefined"
,因此+
变为addition operator,因为其中一个参数是一个字符串,它会连接(字符串版本)另外,不是数学版本),因此0
转换为字符串"0"
并连接到"undefined"
,在字符串"undefined0"
中重新开始。
因此,只要尝试评估具有不可解析引用的表达式(例如未声明或初始化变量),就会引发引用错误,例如
typeof !foo
也会抛出引用错误,因为为了计算传递给 typeof 的内容,必须计算表达式。要应用!
运算符,必须获取 foo 的值,并在尝试时抛出引用错误。
答案 2 :(得分:2)
typeof
没有抛出错误“ReferenceError:foo is not defined”,它被函数本身抛出。如果你曾经使用过:
typeof (function() { return 2; })()
它会按预期返回“数字”,但在此示例中,JavaScript甚至没有达到typeof
正在运行的任何地方。您收到的错误与运行时相同:
function test () {
return foo;
}
test();
答案 3 :(得分:2)
通过规范,我认为当有问题的运算符试图在其操作数上运行GetValue()
时,这一切都归结为。
typeof
attempts to determine its operand's Type
first. If that type is a Reference
and is IsUnresolvableReference()
, then it bails out and returns undefined
.实质上,它没有完全评估操作数;如果确实如此,那么undefined
的任何内容都会抛出异常,所以它会短路并返回一个漂亮有用的字符串。
在示例中,自执行函数和加法运算符调用GetValue
而不首先检查IsUnresolvableReference()
typeof
foo
:they call GetValue
and throw an exception如果引用未解析(在我们的案例中undefined
是{{1}})。 (我想!通过阅读规范,这是我最好的猜测。)
答案 4 :(得分:1)
这是标准行为。 typeof
运算符几乎接受您传递给它的下一个变量的引用。
让我们试试typeof foo
。
javascript解释器查看typeof并找到foo
的类型。
现在我们尝试typeof (function() { return foo })()
javascript解释器查看typeof。由于之后的表达式不是变量,因此它会计算表达式。 (function() { return foo })()
会引发ReferenceError
,因为foo
未定义。如果可以传递varialbe的引用,例如(function() { return *foo })()
,那么这不会发生。
注意:根据这一点,可能会认为typeof (foo)
会抛出错误,因为(foo)
不是变量而必须进行评估,但这是不正确的; typeof (foo)
也将返回&#34; undefined&#34;如果foo没有定义。
本质上,解释器在&#34; safe&#34;中评估下一个变量,但不计算表达式。上下文,以便typeof
不会抛出错误。
这有点令人困惑。