Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
212 views
in Technique[技术] by (71.8m points)

javascript - Why does typeof only sometimes throw ReferenceError?

In Chrome and Firefox,

typeof foo

evalulates to 'undefined'.

But

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

throws an error:

ReferenceError: foo is not defined

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.

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


EDIT:

Another example:

typeof (foo)
typeof (foo + 0)

I would have expect (foo) and (foo + 0) to throw an error.

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

Quoting ECMAScript 5.1 § 11.4.3 The typeof Operator (emphasis added):

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.

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. 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.

Now, analyzing the code:

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

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).

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)

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

Now:

typeof (foo)

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.

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

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. 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.

1 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...