Monday, 19 November, 2018 UTC


Summary

There is a high chance that you’ve stumbled across the JavaScript eval function.  It is a common knowledge that in JavaScript, eval is something that is a bad practice. Have you ever wondered how it works and why exactly a lot of people discourage it? This article covers that and presents some real-life usage of the eval function.
Javascript eval
The eval function takes the JavaScript code in the form of a string and evaluates it. It is quite a dangerous function to use. It is because of the fact it executes the code with the same privileges as the rest of the application. The code ran by eval also uses the same scope. If you use eval with a string that can be in any way affected by someone, you may face the harsh reality of it being malicious. Consider this simple Node.js example:
const { exec } = require('child_process');

const user = {
  name: 'John"); exec("rm -rf ./*"); console.log("'
}

eval(
  `console.log("Username: ${user.name}")`
);
In this example, the eval function receives such a string:
console.log("Username: John"); exec("rm -rf ./*"); console.log("")'
Running it results in deleting all files in the current directory. Another thing it could for instance do is send a request to another server containing some sensitive data like a secret key. All that just because you’ve used a string that a user can edit somewhere in the eval function.
The example with the
rm -rf
 is quite hardcore. If you think you don’t need to treat the code that browser runs with such care, you are quite mistaken. Image a similar injection stealing the contents of the
document.cookie
 of the visitors of your site. It is one of the reasons that storing sensitive data there is not a good reason.
If you would like to know more about cookies, check out Cookies: explaining document.cookie and the Set-Cookie header
JavaScript eval returns the value of the last evaluated expression;
const one = 1;
const two = 2;
const three = 3;

eval('one + two; two + three'); // 5
If you provide it with an argument other than a primitive string, it returns it.
eval({ dogName: 'Fluffy' }); // { dogName: 'Fluffy' }
Performance. Interpreting vs Just In Time compiling
To understand the performance decrease when using eval, we first need to look at how the browser executes JavaScript. The first thing to notice is that the processor does not understand the JavaScript directly. It operates on ones and zeros, the machine code.

Interpreting

In the past, the browsers just interpreted JavaScript. It means that translation from the code that you wrote to the machine code happened pretty much line-by-line, one by one. The advantage of that approach is that the code can start executing straight after you put it into the browser. Because developers used JavaScript for quite simple things, it seemed like a suitable approach. It does have a lot of cons, though. If you are running some code more than once, the browser needs to interpret it every time. Since applications started to get more and more complex, just interpreting the code began to seem like not that good of an idea.

Just In Time compiling

A way to overcome the interpreters’ shortcomings is to compile the code. It takes more time before the browser can run the code, but thanks to that process the code is more optimized. The mechanism that browsers incorporated is called a monitor. At first, the browser runs the code through the interpreter. If you run the same code multiple times, that piece is sent to be compiled by the baseline compiler, and the browser stores the result. This process helps to speed things, but if you continue to execute the code frequently, the browser sends it to the optimizing compiler. It takes some additional time, but your code may end up being even faster. This approach is Just In Time compilation.
If you would like to know more about JIT, read a great article by Lin Clark titled A crash course in just-in-time (JIT) compilers

But what’s with eval?

When you use eval, you make it difficult for the built-in mechanisms to optimize your code.
An important fact already mentioned above is that eval uses the scope in which you called it.
const dogName = 'fluffy';

eval(
  'console.log(dogName)'
);
The compiler prepares the machine code for variables of certain value type. When you use variables from outside of the eval inside of it, the browser is forced to do a timely-expensive variable lookup to check if a variable exists and what is its type.
Real-life usage of eval
Chances are you are familiar with the
JSON.parse
 function. An interesting fact is that browsers didn’t always support it – the ES5 introduced it. Before that, json2.js was a popular implementation done by Douglas Crockford, that was involved in the development of the JavaScript language itself. If you look closely at its source code you will notice eval!
j = eval("(" + text + ")");
It is quite funny because in his code conventions you can read:
eval is evil
The eval function is the most misused feature of JavaScript. Avoid it.
So is eval completely useless? If you know what you are doing, no. The 
JSON.parse
example is quite outdated, but we have some more modern examples.
A good one is Webpack. In my article Webpack 4 course – part six. Increasing development experience I’ve mentioned source maps. Eval-source-map is one of the possible configurations. With it, the browser executes each module using eval and the source map is added accordingly.
eval("console.log('Hello world!');\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9zcmMvaW5kZXguanM/YjYzNSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSIsImZpbGUiOiIwLmpzIiwic291cmNlc0NvbnRlbnQiOlsiY29uc29sZS5sb2coJ0hlbGxvIHdvcmxkIScpO1xuIl0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///0\n");
So in this example, the browser calls the eval function that Webpack generated.
Summary
This article went through the basics of how eval works. It included explaining what are the dangers of using JavaScript eval, taking into consideration how JavaScript is executed by the browser (interpreting or being compiled). The article also pointed out some real-life usages of eval, like the source maps generated by Webpack. Hopefully, this will help you in deciding whether you need to use eval, or not.
The post Is eval evil? Just In Time (JIT) compiling appeared first on Marcin Wanago Blog - JavaScript, both frontend and backend.