为什么typeof有时只抛出ReferenceError? [英] Why does typeof only sometimes throw ReferenceError?

查看:150
本文介绍了为什么typeof有时只抛出ReferenceError?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Chrome和Firefox中,

In Chrome and Firefox,

typeof foo

评估为'undefined'.

但是

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

引发错误:

ReferenceError: foo is not defined

这破坏了我对表达的可替代性的认识!直到现在,我还不知道foo(function() { return foo; })()不同的条件.

This destroys the notions that I have of susbstitutability of expressions! Until now, I knew of no conditions for which foo and (function() { return foo; })() are not the same.

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

Is this standard behavior? If so, it would be helpful to quote the relevant part of the ECMAScript standard.

另一个例子:

typeof (foo)
typeof (foo + 0)

我希望(foo)(foo + 0)会引发错误.

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

But the first one has no error; the second one does.

推荐答案

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

Basically, the typeof operator checks whether a variable¹ is unresolvable and returns "undefined". That is, typeof returns a defined value for undeclared variables¹ before reaching the GetValue algorithm which throws for undeclared variables¹.

引用 ECMAScript 5.1§11.4.3 typeof运算符(强调):

11.4.3运算符的类型

生产 UnaryExpression :typeof UnaryExpression 是 评估如下:

11.4.3 The typeof Operator

The production UnaryExpression : typeof UnaryExpression is evaluated as follows:

  1. val 成为评估 UnaryExpression 的结果.
  2. 如果类型( val )是

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

2.1.如果 IsUnresolvableReference ( val )为true,则返回"undefined".

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

2.2让val为 GetValue ( val ).

2.2 Let val be GetValue(val).

根据类型( val )确定的字符串="http://es5.github.io/#x11.4.3">表20 .

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

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

In the other hand, the return statement -- like most operators and statements which read the value from identifier(s) -- will always call GetValue which throws on unresolvable identifiers (undeclared variables). Quoting ECMAScript 5.1 § 8.7.1 GetValue (V) (emphasis added):

8.7.1 GetValue(V)

  1. 如果类型(V)不是参考,请返回V.
  2. 让基础是调用 GetBase (V)的结果.
  3. 如果 IsUnresolvableReference (V),则引发ReferenceError异常.
  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才对函数的返回值进行操作(函数调用采用

This code will instantiate a function object, execute it and only then typeof will operate on the function's return value (function call takes precedence over the typeof operator).

因此,在评估typeof操作之前,代码在评估IIFE的return语句时抛出.

Hence, the code throws while evaluating the IIFE's return statement, before the typeof operation can be evaluated.

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

A similar but simpler example:

typeof (foo+1)

typeof之前评估加法.当加法运算符typeof起作用之前在foo上调用GetValue时,这将引发错误.

The addition is evaluated before typeof. This will throw an error when the Addition Operator calls GetValue on foo, before typeof comes into play.

现在:

typeof (foo)

不会抛出错误,因为分组运算符(括号)本身不会评估"任何内容,它只是强制优先.更具体地说,分组运算符不调用GetValue.在上面的示例中,它返回(不可解析的)参考.

Does not throw an error as the grouping operator (parentheses) does not "evaluate" anything per se, it just forces precedence. More specifically, the grouping operator does not call GetValue. In the example above it returns an (unresolvable) Reference.

带注释的ES5.1规范甚至对此添加了注释:

The annotated ES5.1 spec even adds a note about this:

注意:该算法不适用于 GetValue 到计算Expression的结果.这样做的主要动机是可以将deletetypeof之类的运算符应用于带括号的表达式.

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.


NB 我写这个答案的重点是提供一个简单易懂的解释,使技术术语降到最低,同时仍然足够清晰,并提供所要求的ECMAScript标准参考.希望对那些难以理解typeof运算符的开发人员提供有用的资源.


N.B. I've wrote this answer with the focus on providing a simple and understandable explanation, keeping the technical jargon to a minimum while still being sufficiently clear and providing the requested ECMAScript standard references, which I hope to be a helpful resource to developers who struggle with understanding the typeof operator.

¹为了易于理解,使用了变量"一词.一个更正确的术语是 identifier ,它不仅可以引入词汇环境通过变量声明,还包括函数声明,形式参数,调用函数(arguments),with/catch块,为全局对象分配属性,letconst语句(ES6),以及其他一些方式.

¹ The term "variable" is used for ease of understanding. A more correct term would be identifier, which can be introduced into a Lexical Environment not only through variable declarations, but also function declarations, formal parameters, calling a function (arguments), with/catch blocks, assigning a property to the global object, let and const statements (ES6), and possibly a few other ways.

这篇关于为什么typeof有时只抛出ReferenceError?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆