为什么重新定义自己的功能在Chrome/IE和Firefox中表现不同?

 show窝_515 发布于 2023-02-05 08:06

请考虑以下代码:

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

我期望f在执行期间始终定义.但是,在Chrome和IE中,它是undefined在第一个console.log被调用时,而在Firefox中,它是undefined在第二个console.log被调用时.

为什么f不总是定义?为什么Chrome/IE和Firefox的行为有所不同?

http://jsfiddle.net/G2Q2g/

Firefox 26上的输出:

在调用f()时,f是:

function f() {
    f = eval("" + f);
    console.log("Inside a call to f(), f is: \n%s", f);
}

在调用f()之后,f是:

undefined

Chrome 31和IE 11上的输出:

在调用f()时,f是:

undefined

在调用f()之后,f是:

function f() {
    f = eval("" + f);
    console.log("Inside a call to f(), f is: \n%s", f);
}

Benjamin Gru.. 8

首先,让我们谈谈我们"期望"的内容.

我会天真地期待两种情况都会回归undefined.

就像:eval("function foo(){}")返回undefined.

就像我们有一个函数声明一样 - 它不返回函数值但是设置它.

就像langue规范所说的严格模式一样.

更新:通过规范挖掘更多 - 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作为参数的结果.

这解释了为什么它在严格模式下工作 - 它都在新环境中运行.


同样的事情,但更多的文字和更少的图形

"查找" ff =(因为左侧必须进行评估,首先,这指的是本地的副本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.

(链接到相关的esdiscuss主题)

1 个回答
  • 首先,让我们谈谈我们"期望"的内容.

    我会天真地期待两种情况都会回归undefined.

    就像:eval("function foo(){}")返回undefined.

    就像我们有一个函数声明一样 - 它不返回函数值但是设置它.

    就像langue规范所说的严格模式一样.

    更新:通过规范挖掘更多 - 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作为参数的结果.

    这解释了为什么它在严格模式下工作 - 它都在新环境中运行.


    同样的事情,但更多的文字和更少的图形

    "查找" ff =(因为左侧必须进行评估,首先,这指的是本地的副本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.

    (链接到相关的esdiscuss主题)

    2023-02-05 08:15 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有