Indirect eval call in strict mode

前端 未结 1 1133
没有蜡笔的小新
没有蜡笔的小新 2020-12-08 06:25

I understand about how eval() works in non-strict contexts, however the case of using eval() in strict mode has completely befuddled me. When

相关标签:
1条回答
  • 2020-12-08 07:00

    tl;dr

    The second (0, eval)('var a = 1;'); case is in fact not a direct call.

    You can see this more prevalently in:

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

    The issue can be seen in:

    If the eval code is strict code, then (me: fix context)

    But strict eval code is defined as:

    Eval code is strict eval code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct call.

    Since the call is not direct, the eval code is not strict eval code - and the execution is on global scope.


    First of all great question.

    "Eval Code" is more general than direct or indirect call to eval.

    Let's check the exact specification for the eval function

    15.1.2.1 eval (x)

    When the eval function is called with one argument x, the following steps are taken:

    1. If Type(x) is not String, return x.

    2. Let prog be the ECMAScript code that is the result of parsing x as a Program. If the parse fails, throw a SyntaxError exception (but see also clause 16).

    3. Let evalCtx be the result of establishing a new execution context (10.4.2) for the eval code prog.

    4. Let result be the result of evaluating the program prog.

    5. Exit the running execution context evalCtx, restoring the previous execution context. ...

    So, let's explore what 10.4.2 tells us, you cited that - in specific let's look at the first clause:

    If there is no calling context or if the eval code is not being evaluated by a direct call (15.1.2.1.1) to the eval function then ... Initialise the execution context as if it was a global execution context

    So what is a direct call?

    A direct call to the eval function is one that is expressed as a CallExpression that meets the following two conditions:

    The Reference that is the result of evaluating the MemberExpression in the CallExpression has an environment record as its base value and its reference name is "eval".

    The result of calling the abstract operation GetValue with that Reference as the argument is the standard built-in function defined in 15.1.2.1.

    So, what's the MemberExpression in both cases?

    In eval('var a = 1;'); indeed the result of evaluating it has a reference name eval and calling GetValue resolution on it returns the built in function.

    In (0, eval)('var a = 1;'); the result of evaluating the member expression does not have a reference name eval. (It does resolve to the built in function on GetValue though).

    What are reference names anyway?

    Section 8.7 in the spec tells us:

    A Reference is a resolved name binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1). A base value of undefined indicates that the reference could not be resolved to a binding. The referenced name is a String.

    This requires us to look into the GetReferencedName:

    GetReferencedName(V). Returns the referenced name component of the reference V.

    So, while the expression (0,eval) === eval is true, when evaluating the function, this is actually an indirect call because of naming.

    May I offer the Function constructor instead :)?

    0 讨论(0)
提交回复
热议问题