请考虑以下代码:
function f() {
f = eval("" + f);
console.log("Inside a call to f(), f is: \n%s", f);
}
f();
console.log("After a call to f(), f is: \n%s", f);
Run Code Online (Sandbox Code Playgroud)
我期望f在执行期间始终定义.但是,在Chrome和IE中,它是undefined在第一个console.log被调用时,而在Firefox中,它是undefined在第二个console.log被调用时.
为什么f不总是定义?为什么Chrome/IE和Firefox的行为有所不同?
Firefox 26上的输出:
在调用f()时,f是:
Run Code Online (Sandbox Code Playgroud)function f() { f = eval("" + f); console.log("Inside a call to f(), f is: \n%s", f); }在调用f()之后,f是:
Run Code Online (Sandbox Code Playgroud)undefined
Chrome 31和IE 11上的输出:
在调用f()时,f是:
Run Code Online (Sandbox Code Playgroud)undefined在调用f()之后,f是:
Run Code Online (Sandbox Code Playgroud)function f() { f = eval("" + f); console.log("Inside a call to f(), f is: \n%s", f); }
首先,让我们谈谈我们"期望"的内容.
我会天真地期待两种情况都会回归undefined.
就像:eval("function foo(){}")返回undefined.
就像我们有一个函数声明一样 - 它不返回函数值但是设置它.
更新:通过规范挖掘更多 - Firefox在这里是正确的.
这是Firefox正在做的事情
可视化:
- f
= eval("" + f);//将左侧设置为f我们所在的函数f =eval(""+ f); //f在此函数的范围内声明一个新函数f = undefined;//自undefined === eval("function(){}");*
*因为函数声明不返回任何东西 - 就像函数foo(){}没有返回值一样
由于f是在步骤1中决定的,所以现在对我们所使用的函数的引用被undefined覆盖,并且声明的局部闭包f用相同的代码声明.现在我们这样做:
console.log("Inside a call to f(), f is: \n%s",f)// f是局部闭包变量,它最接近
突然间,很明显我们得到了函数 - 它是一个成员变量.
但是,一旦我们逃脱了这个功能
console.log("After a call to f(), f is: \n%s",F);
这里,f是未定义的,因为我们在步骤1中覆盖了它.
Chrome和IE错误地将其分配给错误f并在分配左侧之前评估右侧.
请注意,下一节在输入eval代码中说明:
让strictVarEnv成为调用NewDeclarativeEnvironment传递LexicalEnvironment作为参数的结果.
这解释了为什么它在严格模式下工作 - 它都在新环境中运行.
同样的事情,但更多的文字和更少的图形
f从f =(因为左侧必须进行评估,首先,这指的是本地的副本f,也就是说,首先评估左手边.eval返回的调用,undefined但声明一个新的本地函数f.ffrom f =在函数本身之前被评估,当我们为它分配undefined时,我们实际上正在替换全局函数console.log内部时,我们指的是在eval中声明的本地副本,因为它在范围链中更接近.console.log,我们现在指的f是我们指定未定义的'全局' .诀窍是,我们分配的f和我们记录的f是两个不同的fs.这是因为总是首先评估赋值的左侧(规范中的第11.13.1节).
IE和Chrome错误地分配给本地f.由于规范明确告诉我们,这显然是不正确的:
让lref成为评估LeftHandSideExpression的结果.
让rref成为评估AssignmentExpression的结果.
因此,正如我们所看到的那样,首先需要评估lref.
| 归档时间: |
|
| 查看次数: |
332 次 |
| 最近记录: |