Home  >  Article  >  Web Front-end  >  JavaScript cheats lexical eval, with and catch and their performance issues

JavaScript cheats lexical eval, with and catch and their performance issues

黄舟
黄舟Original
2017-02-28 14:58:471365browse

Normally speaking, the scope chain of the execution context will not change

The lexical scope in JavaScript is not static
(lexical scope/static scope: The scope is determined by the function declaration position when writing the code)
There are several mechanisms that can deceive the lexicon
They are with(), eval() and the catch clause of the try-catch statement
where with We should not use eval and eval (it will cause a lot of problems)
Cheating lexical means cheating lexical scope
In other words, they change the scope chain at runtime
Let me talk about it below These mechanisms that can deceive lexicon

eval

eval() function accepts a string as a parameter, and parses the string to generate code

var a = 123;eval('console.log(a)');// 123

So the console printed 123
After executing the eval function
The js engine does not know that this code was dynamically inserted and the scope chain was modified
The engine will also look for the scope chain as usual
Look at the following code

var a = 1;function demo(){
    eval('var a = 2;');//欺骗词法
    console.log(a);// 2}
demo();

When the eval function is executed, the variable a is added to the top scope of the demo function execution environment
a in this local environment "shadows" a in the global environment
Eventually causes the program to print 2

The eval() function can not only modify the scope it is currently in, but can even modify the global scope
No matter what, it can modify the lexical scope during runtime

ES5's strict mode adds some restrictions to this function. I added the local strict mode to the above code

var a = 1;function demo(){    'use strict';    eval('var a = 2;');
    console.log(a);// 1}
demo();

We found that this time the console printed 1
This is because in strict mode, eval() has its own independent lexical scope when running (to save it from messing up the scope chain of the execution environment)
In this way, the declaration in it cannot modify the scope in which it is located

This can There are two other ways to dynamically generate code that are very similar to it
The first parameter of timers setTimeout() and setInterval() can be a code string
The same is true for the last parameter of function constructor new Function() Accepting code strings
is the same as eval(). Do not use this usage. This will cause serious performance problems. We will discuss this issue later.

with

Another one is not recommended. The deceptive lexical syntax is the with keyword
with is usually used as a shortcut to repeatedly reference multiple properties of an object
The advantage is that there is no need to repeatedly reference the object itself
For example, I want to reuse console object

console.log(1);console.info(2);console.warn(3);

Use the with keyword

with(console){    log(1);    info(2);    warn(3);
}

JavaScript cheats lexical eval, with and catch and their performance issues

It seems that there is no problem with with, but looking at the following

function demo(obj){
    with(obj){
        a = 5;
    }
}var obj1 = {a:1};var obj2 = {b:2};

demo(obj1);
console.log(obj1.a);// 5demo(obj2);
console.log(obj2.a);// undefinedconsole.log(a);//5 -->变量a居然泄漏到了全局环境

we find that using with The keyword modifies the a of obj1
But not only does it not add a to obj2, but it produces side effects and leaks to the global
This is because with can process an object into a completely isolated lexical scope (put it in the scope The front of the domain chain)
So execution occurs inside it a = 5;
It will look down the scope chain, but not found, so a variable a is created globally ( No declaration of var)

Note: Although with creates a lexical scope, normal var declarations inside with will not be restricted to this block scope
That is to say, declarations outside with Scope
Like this

function demo(){
    var obj = {};    with(obj){        var b = 1;
        console.log(b); // 1
    }
    console.log(b); // 1}
demo();
console.log(b);// Uncaught ReferenceError: b is not defined

And the with keyword is simply not allowed to be used in the strict mode of ES5
If you try to use it, you will see an error like this:

JavaScript cheats lexical eval, with and catch and their performance issues

catch

In addition to eval and with, the catch clause in the try-catch statement can also modify the scope chain of the execution environment
When an error occurs in the try code block , the execution flow immediately jumps to the catch clause
Then the exception object is pushed into a mutable object and placed at the front of the scope chain, which is very similar to with
Once the catch clause is executed, The scope chain will be restored to its original state

But unlike eval and with, try-catch is still relatively useful and does not need to be abandoned completely (although I have not used it)

Performance

Deception of lexicon will cause performance problems
The js engine will perform performance optimization during the compilation phase. Many optimizations rely on the ability to perform static analysis based on code lexicon
The definition locations of variables and functions are determined in advance, so that the logo can be quickly found symbol
But eval or with cannot determine the position of the identifier (it exists during code execution and cannot be statically analyzed)
In other words: In front of eval and with, all the optimizations of the js engine are meaningless (Simply cool)
Since it makes no sense, the js engine simply won’t be optimized
This will cause the program to run slower

For with, it also has its own unique performance issues...
Generating a scope will cause all local variables of the function in which it is located to be in the second scope chain object
The access cost is higher

For the try-catch statement, if we want Use, you can do this

try{    ...}catch(e){
    handleError(e);
}

Only a piece of code is executed in the catch statement, and it is delegated to a function to handle errors
In this way, there is no access to local variables
Temporary changes in the scope chain will not Will affect performance

Summary

Summary the key points

  • Lexical scope means that the scope is determined by the position of the function declaration when writing the code
    The compile-time lexical analysis phase can know where and how all identifiers are declared

  • eval can be evaluated on code strings, thereby modifying the lexical scope at runtime

  • with treats an object reference as a scope, This creates a lexical scope at runtime

  • eval will generate an independent lexical scope in strict mode, and the scope cannot be modified

  • with is prohibited from being used in strict mode

  • eval and with (and catch) can deceive the lexicon and modify the scope chain during execution

  • eval and with cause the js engine to be unable to optimize the scope search during the compilation phase (cannot be statically analyzed), causing the program to slow down.

Having said so much, I want to tell everyone not to use the with key Words and eval functions~( ̄0 ̄)/

The above is the content of JavaScript’s deceptive lexical eval, with and catch and its performance issues. For more related content, please pay attention to the PHP Chinese website (m.sbmmt.com )!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn