Unravel eval in closure

 

"Once there was a beautiful girl named Snow White, who lived with seven dwarfs, and they lived Happily Ever After." Obviously, a villain will come out to strike this kind of boring peace. In Javascript,eval plays a role notwithstanding pile of preachers and moralists propound lots of articles to evict it in practical use to keep Snow White safe.   

Nobody would not be confused by abstract conception which could not be organized succinctly. Before intro to eval,one thing should be avoid: test eval in developer console tool in developer tools of every browser. Because of these security issues, some web servers use the HTTP “Content-Security-Policy” header to disable eval() for an entire website. 

 

 

How eval works 

Like many interpreted languages, JavaScript has the ability to interpret strings of JavaScript source code, evaluating them to produce a value. JavaScript does this with the global function eval(): 

console.log(eval("3+2"))   // => 5 

 

eval() expects one argument. If you pass any value other than a string, it simply returns that value. If you pass a string, it attempts to parse the string as JavaScript code, throwing a SyntaxError if it fails. If it successfully parses the string, then it evaluates the code and returns the value of the last expression or statement in the string or undefined if the last expression or statement had no value. If the evaluated string throws an exception, that exception propagates from the call to eval() 

 

 

Confusing global eval 

Before going further, let’s define “global eval” as a way to evaluate code in global scope. Simple as that. 

The reason for all this fuss about evaluating code in global scope is because global, built-in eval function evaluates code in the scope of a caller: 

var x = 'outer'; 
 

(function() { 
    var x = 'inner'; 
    eval('x');   })(); 

 

// =>inner 

 

    

So native eval doesn’t allow to execute code globally. What to do? Indirect call is a  solution. 

 

Direct call  vs indirect call 

 

const geval = eval; // Using another name does a global eval  

let x = "global", y = "global"; // Two global variables  

function f() { // This function does a local eval  

let x = "local"; // Define a local variable  

eval("x += 'changed';"); // Direct eval sets local variable  

return x; // Return changed local variable  

 

function g() { // This function does a global eval  

let y = "local"; // A local variable  

geval("y += 'changed';"); // Indirect eval sets global variable  

return y; // Return unchanged local variable  

 

console.log(f(), x); // Local variable changed: prints "localchanged global":  

console.log(g(), y); // Global variable changed: prints "local globalchanged":  

 

 

Indirect call has never physical touch with local variable, but direct call perform oppositely. It is not necessary to dissection the accurate conception to process above code and get its output. Literally,   A “direct eval” is a call to the eval() function with an expression that uses the exact, unqualified name “eval” (which is beginning to feel like a reserved word). Direct calls to eval() use the variable environment of the calling context. Any other call—an indirect call—uses the global object as its variable environment and cannot read, write, or define local variables or functions. (Both direct and indirect calls can define new variables only with var. Uses of let and const inside an evaluated string create variables and constants that are local to the evaluation and do not alter the calling or global environment.)The conception is cryptic and difficult to reach its nitty-gritty.Scroll down example to forge indirect conception in the mind. 

 

Indirect examples: 

(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')('...') 




 

 

Direct call and indirect call in strict mode 

Strict mode in eval is a little different with normal. Code passed to  the eval() method is strict code if eval() is called from strict code or if the string of  code includes a "use strict" directive. Take a example: 

 

        Two kinds of strict mode 

 

'use strict'; 
eval('var a = 1;'); 
console.log(a);  

// ReferenceError: a is not defined 

 

eval("'use strict'; var a = 1;");  

console.log(a); 

// ReferenceError: a is not defined 

 

             

When eval() is called from  strict-mode code, or when the string of code to be evaluated itself begins with a “use  strict” directive, then eval() does a local eval with a private variable environment.  In non-strict mode, Instead, variable and function definitions created in the eval() live in a new scope outside eval. But without declaration, no difference for strict or no-strict mode. In one word, strict mode only perform in declaration within eval's direct call. Please see the examples of comparison: 

 

Direct call&declaration in strict vs normal mode 

 

console.log(eval("'use strict';var a = 1;a"));   

console.log(a) 

//1 

// ReferenceError: a is not defined 

 

console.log(eval("var a = 1;a"));   

console.log(a) 

//1 

//1 

 

 

 

                     Direct all in strict vs normal mode 

 

let x = "global";  

  

function f() {   

  

let x = "local";  

  

eval("'use strict';x += 'changed';");  

  

return x;  

}   

console.log(f(), x);  

//"localchanged" "global" 

let x = "global";  

  

function f() {   

  

let x = "local";  

  

eval("'use strict';x += 'changed';");  

  

return x;  

}   

console.log(f(), x);  

//"localchanged" "global" 

 

 

Indirect call&declaration within in strict and non-strict mode 

 

'use strict'; 
(0, eval)('var a = 1;'); // indirect call to eval 
console.log(a); // 1 

 

 

(0, eval)('var a = 1;'); // indirect call to eval 
console.log(a);//1 

 

 

 

Indirect call in strict and non-strict mode 

 

"use strict" 

const geval = eval;    

  

let x = "global", y = "global";  

function g() {    

  

let y = "local";  

  

(0,eval)("y += 'changed';"); return y; }   

console.log(g(), y);  

 

//"local" "globalchanged" 

 

 

const geval = eval;    

  

let x = "global", y = "global";  

function g() {    

  

let y = "local";  

  

(0,eval)("y += 'changed';"); return y; }   

console.log(g(), y);  

 

//"local" "globalchanged" 

 

 

Summary 

global eval  haunts in javascript closure and become so intriguing with indirect all and mutant strict mode that closure could not be cozy ostensibly like before. And use of eval hidden  its connivence and its indispensability under its confusion. Wish thematic of this this article could be fire to burn all obstruction and ice to reflect its essence leading to use.       


Comments