Thoughts caused by eval(...) !== (1,eval)(...)

Let's look at an example
var x = 'outer';
(function() {
  var x = 'inner';
  eval('console.log("direct call: " + x)');
  (1,eval)('console.log("indirect call: " + x)');
})();

the answer is:
direct call: inner
indirect call: outer



eval('1+1') is a direct eval call, while (1,eval)('1+1') is not. Since the latter is not a direct call, it is an indirect eval call.
( 1 , eval ) ( '1+1' )
     |____| |_____| |_____|
       Constant Operator Identifier

     |_________________________|
      Expression

  |_____________________________|
    Main Expression

  |____________________________| |________|
   Member Expression Argument

  |________________________________________________|
   Invocation Expression
In the above example, it is clear what part before the parameter (invocation parenthesis) does not consist only of the "eval" identifier. This is a complete other type of expression consisting of the comma operator, the numeric constant, and then the "eval" identifier. 1, eval - based on how the comma operator works - still executes a standard built-in eval function, but the entire expression is no longer called directly. So it is an indirect eval call.

(1, eval)('...')
(eval, eval)('...')
(1 ? eval : 0)('...')
(__ = eval)('...')
var e = eval; e('...')
(function(e) { e('.. .') })(eval)
(function(e) { return e })(eval)('...')
(function() { arguments[0]('...') })(eval)
this .eval('...')
this['eval']('...')
[eval][0]('...')
eval.call(this, '...')
eval(' eval')('...')
According to ES5, all of these are indirect calls and should be executed in the global scope. Did you notice that the ES5 definition states that evals that call expressions should execute standard, built-in functions? This means that eval('1+1') must not be called directly depending on the context. A call is considered a direct call only when eval actually (not overriding or implicitly) refers to a standard, built-in function.
eval = (function(eval) {
    return function(expr) {
      return eval(expr);
    };
  })(eval);

  eval('1+1'); // It looks like a direct call, but is actually an indirect call.
               // This is because `eval` resolves to a custom function, not a standard, built-in function.


eval('...')
  (eval)('...')
  (((eval)))('...')
  (function() { return eval('...') })()
  eval('eval("...")')
  (function(eval) { return eval('...'); })(eval)
  with({ eval: eval }) eval('...')
  with(window) eval('...')
seems pretty straightforward, doesn't it?
But wait, why do you think (eval)('...') and (((eval)))('...') are direct calls? Of course, they don't obey the feature we established earlier - there are "eval" identifiers inside member expressions inside call expressions. What the hell is going on here? Is it the parentheses around eval that make it an indirect call?

The answer to this somewhat subtle question lies in the first paragraph of the ES5 direct call definition - the fact that "eval" in a call expression should be a reference, not a value. During program execution, the eval in the eval('1+1') expression is nothing but a reference, and a value needs to be calculated. Once computed, this value is (most likely) a standard, built-in function object. What happens in the (1,eval)('1+1') indirect call that has been analyzed earlier is (1, eval) expression evaluates to a value, not a reference.
Since it evaluates not a reference, it cannot be considered a direct eval call.
But what about (eval)('1+1')?

The reason that (eval) is considered a direct call is because the (eval) expression still evaluates to a reference, not a value. The same goes for ((eval)), (((eval))), etc. This situation arises because the grouping operators - "(" and ")" - cannot evaluate expressions on their own. If you pass a reference to the grouping operators - "(" and ")" - it still evaluates to a reference, not a value.

eval(); // <-- calls the expression to the left of the parentheses — "eval" — evaluates a reference
  (eval)(); // <-- calls the expression to the left of the parentheses — "(eval)" -- evaluates a reference
  (((eval)))(); // <-- call the expression to the left of the parentheses — "(((eval)))" — evaluates a reference
  (1,eval)(); // <- - calls the expression to the left of the parentheses — "(1, eval)" — evaluates a value
  (eval = eval)(); // <-- calls the expression to the left of the parentheses — "(eval = eval)" — evaluates A value,
as ECMAScript says, is because two operators - the comma operator (in (1,eval)) and the equals operator (in (eval=eval)) - execute on its operands GetValue. So (1,eval) and (eval = eval) compute a value, and eval and (eval) compute a reference.

Now hopefully it's clear that (eval)('...') and (function(eval){ retuan eval('...')})(eval) are direct eval calls, while (1,

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326604891&siteId=291194637