This week I had the pleasure to get to know more about the infamous eval()
function, as it was my first instinct to use it for arithmetic evaluation. We ended up using a third-party library for that matter, but I'd like to shed some light on that topic.
So eval()
is a global Javascript function that evaluates a string as a command. If a string represents an expression, the function will evaluate it as an expression:
eval('1+1') // returns 2
and if it is a statment or a sequance of statements, it will evaluate the last statement:
eval('var x = 5; alert(x)') // triggers alert
Also, I need to mention that eval()
uses the scope in which it is called.
Risks
The main reason you should avoid using it is a security. Evaluating JavaScript code from a string is hazardous. A string may consist of malicious code that will be run on the user's machine, and the scope, where eval()
was called will be exposed for possible attacks.
Especially it is dangerous if you try to evaluate the user's input, that can lead to infinite loops, deleting files or steeling administrative cookies.
For example evaluating the string in Node.js would delete all the files in the current directory:
const valueFromInput = `require("child_process").exec('rm -rf ./*')`;
eval(`console.log("User input: ${valueFromInput}")`);
The second reason is performance. Calling eval()
will be slower than using alternatives, because it has to call JavaScript interpreter, which will convert evaluated code to the machine language. That means if you run the code more than once, the browser will have to interpret the same code again, which is highly inefficient.
Moreover, changing the type of the variable through eval()
will force the browser re-run the code. And using variables that are not in scope with eval()
will require for the browser to do an expensive lookup to check whether the variable exists.
Alternatives
The most simple alternative is to use windows.Function()
. It creates a global scope function from the string. This way, you can write your custom parser to evaluate the code from the string. It is less likely for the possible attacks to do harm comparing with eval()
.
function parse(str) {
return Function(`'use strict'; return (${str})`)()
}
parse('4.12345 * 3.2344 - 9') // 4.336886679999999
In the example above, we are creating a function from the string using strict mode. Which makes it easier to write "secure" JavaScript, for example, you can't use undeclared variables.
Other alternatives that do not use eval()
:
- expression-eval - JavaScript expression parsing and evaluation.
- math.js - Extensive math library for JavaScript and Node.js
Sum Up
eval()
function is rarely used in the modern JavaScript because of its high vulnerability and performance reasons. Misusing the function can lead to running malicious code on the user's machine and data loss. There are third-party alternatives that will fool-proof a string evaluation to JavaScript, and for simple usage, you can use global Function()
to write your own custom evaluation function.
Top comments (6)
Hi Linas,
While using Function, I am getting issue as "args is not defined".
As my string is in the object and the value is "hello, my name is ${arg[0]}."
I am also passing the arg to this runtime object. Don't know what is the issue and how argument will be fetched. Could you help me with this ?
With eval() it works fine
I'm running into an issue where I keep getting,
Unexpected token 'const'
I think it's because you are using
const
in the string.In the expression, you are returning an expression. You cannot return a
const
. Just pass in a simple expression like2+5
or something like a ternary operatorRe: all "the possible attacks". It has me thinking, after serious review I should abandon internet connectivity entirely, as well as membership of literally any community, because I honestly see no way to fully block "the possible attacks". Please advise on this matter!
Separately and topic-relevant: eval is simply a handy built-in function for... you guessed it! EVALUATING code in string form, wherever the eval call is placed. That is, you mention scope and invoking new interpreters etc. But code passed to eval (which can be a great deal larger than several statements), is executed just as if it was coded verbatim, which affords the ability to PROGRAMATICALLY generate and execute code. HOWEVER, you correctly identified a performance opportunity, in that eval tends to run things more slowly than native code. There are many alternatives to eval, like the one you pointed out, which can eliminate the performance hit.
I dislike any article that paints a function, tool, or language in a negative light. No one is forcing anyone to use eval... It's just there as a quick and dirty OPTION. understanding its limitations empowers you to use it appropriately, like anything else.
Great writeup, otherwise!
Someone on stack exchange said "Don't use the window function". But they didn't give a reason. What are the risks?
Thanks man! Save me a ton, I'm building a calculator app with React and keep getting the "eval can be harmful" "no-eval" warning. Thanks!