Javascript 严格模式下的间接评估调用

Javascript 严格模式下的间接评估调用,javascript,eval,ecmascript-5,Javascript,Eval,Ecmascript 5,我了解eval()如何在非严格上下文中工作,但是在严格模式下使用eval()的情况完全让我困惑。当在全局范围内直接调用eval()时,变量将保留在新的eval()范围内: 'use strict'; eval('var a = 1;'); console.log(a); // ReferenceError: a is not defined 但是,如果我在全局范围内执行对eval()的间接调用(应该是相同的,对吧?),它的行为就好像它不是在严格模式下(如果您不相信我,请参阅): 如果您不了解(

我了解
eval()
如何在非严格上下文中工作,但是在严格模式下使用
eval()
的情况完全让我困惑。当在全局范围内直接调用
eval()
时,变量将保留在新的
eval()
范围内:

'use strict';
eval('var a = 1;');
console.log(a); // ReferenceError: a is not defined
但是,如果我在全局范围内执行对
eval()
的间接调用(应该是相同的,对吧?),它的行为就好像它不是在严格模式下(如果您不相信我,请参阅):

如果您不了解
(0,eval)
的作用,请参阅

至少根据我对
eval()
如何在严格模式下工作的理解,它意味着(无论是直接调用还是间接调用
eval()
)为
eval()
调用中定义的变量创建一个新的作用域,但这里的情况似乎不是这样。规范说明如下:

输入评估代码 当控件进入eval代码的执行上下文时,将执行以下步骤:

  • 如果没有调用上下文,或者eval代码没有被eval函数的直接调用()计算,那么

    a。初始化执行上下文,就像它是一个全局执行上下文一样,使用评估代码C,如中所述

  • 否则,

    a。将设置为与调用执行上下文相同的值。
    B将设置为与调用执行上下文相同的值。
    C将设置为与调用执行上下文的值相同的值

  • 如果评估代码为,则

    a。将strictVarEnv作为调用的结果,并将其作为参数传递。
    B将设置为strictVarEnv。
    C将设置为strictVarEnv

  • 按照使用评估代码中的说明执行

  • 所有主要浏览器都是如此,包括(但不限于)Internet Explorer 10、Chrome 30和Firefox 24,因为它们都有相同的行为,我不认为这是一个bug。他们不是都要做同一件事吗?如果不是,为什么会这样

    注意:请不要告诉我不要使用
    eval()
    (是的,我知道使用
    eval()
    )的“危险”-我只是想了解这背后的逻辑,这让我完全困惑。

    tl;博士 第二个
    (0,eval)('var a=1;')大小写实际上不是直接调用

    您可以在以下内容中更普遍地看到这一点:

    (function(){ "use strict"
        var x = eval;
        x("var y = 10"); // look at me all indirect
        window.y;// 10
        eval("var y = 11");
        window.y;// still 10, direct call in strict mode gets a new context
    })();
    
    这一问题可以从以下方面看出:

    如果eval代码是严格的代码,那么(me:fix-context)

    但严格的评估代码定义为:

    如果Eval代码以包含Use strict指令的指令序言开头,或者对Eval的调用是直接调用,则Eval代码为严格Eval代码

    因为调用不是直接的,所以eval代码不是严格的eval代码,执行是在全局范围内的


    首先是个好问题

    “Eval Code”比直接或间接调用Eval更通用

    让我们检查一下确切的规格

    15.1.2.1评估(x)

    使用一个参数x调用eval函数时,将执行以下步骤:

  • 如果类型(x)不是字符串,则返回x

  • 让prog成为ECMAScript代码,它是将x解析为程序的结果。如果解析失败,抛出SyntaxError异常(但也请参见第16条)

  • 让evalCtx成为为eval代码程序建立新执行上下文的结果

  • 让结果作为评估程序进度的结果

  • 退出正在运行的执行上下文evalCtx,恢复以前的执行上下文。

  • 那么,让我们来探讨10.4.2告诉我们的内容,您引用了-具体来说,让我们看看第一条:

    如果没有调用上下文,或者如果对eval函数的直接调用(15.1.2.1.1)未对eval代码求值,则。。。初始化执行上下文,就像它是全局执行上下文一样

    那么什么是直拨电话? 对eval函数的直接调用表示为满足以下两个条件的CallExpression:

    作为对CallExpression中的MemberExpression求值的结果的引用有一个环境记录作为其基值,其引用名称为“eval”

    以该引用作为参数调用抽象操作GetValue的结果是15.1.2.1中定义的标准内置函数

    那么,这两种情况下的
    成员表达式是什么

    eval('var a=1;')
    实际上,对其求值的结果有一个引用名
    eval
    ,对其调用
    GetValue
    resolution将返回内置函数

    (0,eval)('var a=1;')计算成员表达式的结果没有引用名称
    eval
    。(但它确实解析为GetValue上的内置函数)

    引用名称是什么? 第二节告诉我们:

    引用是已解析的名称绑定。引用由三个组件组成:基值、引用名称和布尔值严格引用标志。基值可以是未定义的、对象、布尔值、字符串、数字或环境记录(10.2.1)。未定义的基值表示无法将引用解析为绑定。引用的名称是一个字符串

    这需要我们查看
    getReferenceName

    GetReferencedName(V)。返回引用V的引用名称组件

    因此,虽然表达式
    (0,eval)===eval
    为真,但在计算函数时,由于命名的原因,这实际上是一个间接调用


    我可以提供
    函数
    构造函数吗:)?我觉得这是个bug。你是如何执行代码的
    (function(){ "use strict"
        var x = eval;
        x("var y = 10"); // look at me all indirect
        window.y;// 10
        eval("var y = 11");
        window.y;// still 10, direct call in strict mode gets a new context
    })();