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'; // 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
|
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
Post a Comment