Pau*_*per 10 javascript expression typeof language-lawyer referenceerror
在Chrome和Firefox中
typeof foo
Run Code Online (Sandbox Code Playgroud)
评估为'undefined'.
但
typeof (function() { return foo; })()
Run Code Online (Sandbox Code Playgroud)
抛出错误:
ReferenceError: foo is not defined
Run Code Online (Sandbox Code Playgroud)
这破坏了我对表达式可疑性的概念!到现在为止,我知道没有条件,这foo和(function() { return foo; })()是不一样的.
这是标准行为吗?如果是这样,引用ECMAScript标准的相关部分会很有帮助.
编辑:
另一个例子:
typeof (foo)
typeof (foo + 0)
Run Code Online (Sandbox Code Playgroud)
我希望(foo)并(foo + 0)抛出一个错误.
但第一个没有错误; 第二个.
Fab*_*tté 17
基本上,typeof操作员检查变量¹是否无法解析并返回"undefined".也就是说,typeof在到达未声明变量¹的GetValue算法之前,返回未声明变量¹的定义值.
引用ECMAScript5.1§11.4.3运营商类型(重点增加):
11.4.3运营商的类型
生产UnaryExpression:
typeofUnaryExpression的计算方法如下:
另一方面,return语句 - 就像大多数操作符和从标识符中读取值的语句一样 - 将始终调用GetValue哪些抛出不可解析的标识符(未声明的变量).引用ECMAScript5.1§8.7.1GetValue(V)(重点补充):
8.7.1 GetValue(V)
- 如果类型(V)不是参考,则返回V.
- 设base是调用GetBase(V)的结果.
- 如果是IsUnresolvableReference(V),则抛出
ReferenceError异常.
现在,分析代码:
typeof (function() { return foo; })()
Run Code Online (Sandbox Code Playgroud)
此代码将实例化一个函数对象,执行它,然后typeof才会对函数的返回值进行操作(函数调用优先于typeof运算符).
因此,在评估操作return之前,代码会在评估IIFE 语句时抛出typeof.
一个类似但更简单的例子:
typeof (foo+1)
Run Code Online (Sandbox Code Playgroud)
之前评估添加typeof.当这将抛出一个错误加法运算符要求GetValue的foo,之前typeof进场.
现在:
typeof (foo)
Run Code Online (Sandbox Code Playgroud)
不会抛出错误,因为分组操作符(括号)本身并不"评估"任何内容,它只会强制优先级.更具体地说,分组操作员不会打电话GetValue.在上面的示例中,它返回一个(不可解析的)引用.
带注释的ES5.1规范甚至添加了一个关于此的注释:
注意此算法不适
GetValue用于评估Expression的结果.这样做的主要动机是使运算符如delete和typeof可以应用于带括号的表达式.
NB我写了这个答案,重点是提供一个简单易懂的解释,将技术术语保持在最低限度,同时仍然足够清晰并提供所要求的ECMAScript标准参考,我希望这对于那些奋斗的开发人员来说是一个有用的资源.了解typeof运营商.
¹术语"变量"用于便于理解.一个更正确的术语是标识符,它不仅可以通过变量声明引入词法环境,还可以引入函数声明,形式参数,调用函数(arguments),with/ catch块,将属性赋值给全局对象,let以及const语句( ES6),可能还有其他一些方法.
这是标准行为吗?
是.typeof不会抛出错误,因为它只返回指定的值.但是,正如其他答案所述,代码在评估操作数时失败.
如果是这样,引用ECMAScript标准的相关部分会很有帮助.
在计算函数表达式时,尝试解析foo的值(以便可以返回它)将使用参数foo调用内部GetValue方法.但是,由于未声明或以其他方式创建foo,因此会引发引用错误.
如果是:
typeof (foo)
Run Code Online (Sandbox Code Playgroud)
"("和")"是标点符号,表示分组,例如在调用函数时可能为空的参数列表foo(a, b),或者表示要评估的表达式,例如if (x < 0)等等.
在typeof (foo)他们简单地表示在应用typeof运算符之前评估foo的情况下.因此,作为有效标识符的foo被传递给typeof,上面的每个链接尝试解析它,不能确定它是不可解析的引用,并返回字符串"undefined".
如果是:
typeof (foo + 0)
Run Code Online (Sandbox Code Playgroud)
括号导致foo + 0首先计算表达式.获取foo的值时,会抛出引用错误,因此typeof无法运行.请注意,没有括号:
typeof foo + 0 // undefined0
Run Code Online (Sandbox Code Playgroud)
因为运算符优先级:typeof foo返回字符串"undefined",所以+成为加法运算符,因为其中一个参数是一个字符串,它做连接(加法的字符串版本,而不是数学版本),所以0转换为字符串"0"并连接到"undefined",重新进入字符串"undefined0".
因此,只要尝试使用不可解析的引用来评估表达式(例如,未声明或初始化的变量),就会抛出引用错误,例如
typeof !foo
Run Code Online (Sandbox Code Playgroud)
抛出引用错误也是因为为了找出要传递给typeof的内容,必须对表达式求值.要应用!运算符,必须获取foo的值,并在尝试时抛出引用错误.
| 归档时间: |
|
| 查看次数: |
1682 次 |
| 最近记录: |