Is the eval() function safe to use here? - javascript

I'm learning DOM Scripting with JavaScript and thought it nice to make a simple calculator app, I found the logic easy enough to do but ran into a problem using parseInt to convert the string type arithmetic expression to number type arithmetic expression.
I ended up having to use the eval() function which worked fine for a basic calculator app but on further research I found out the eval() function is a security risk in most casese, I've used a regex expression to cleanse the result but don't know if this is safe enough.
Here is the code snippet I'm unsure is safe to be executed on the client browser.
const equals = document.getElementById("equals");
equals.addEventListener("click", (e) => {
document.getElementById("result").innerText = eval(document.getElementById("result").innerText).replace(/[^**-+/*\d]/g, '');
});
NOTE: This code is deployed as a static site on Netlify.

You should definitely stop using eval().
Executing JavaScript instructions from a string opens up a huge security risk that makes it easy for would-be third-party attackers to inject potentially malicious code into your application without your knowledge or permission.
Another reason not to use eval(), in my view, is that some sources have already marked it as obsolete or deprecated and it is being blocked by default in some environments due to its security risks and slow performance. In other words, support for eval() is at issue and there is a push to possibly phase it out from future versions of Javascript. That means anything you've built that uses it has the potential to eventually stop working.
The good news is eval() has been on its way out for a quite while now so there are plenty of much better, much more secure ways to accomplish just about everything you'd use eval() for. In fact, the code snippet you shared doesn't need eval() at all.
The innerText property you are updating is directly accessible from within the DOM. While we're on the subject, avoid using the innerHTML property. It too poses security risks similar to eval().
This code here should address your concerns:
const equals = document.getElementById("equals");
equals.addEventListener("click", (e) => {
let result = document.getElementById("result");
result.innerText = result.innerText.replace(/[^**-+/*\d]/g, '');
return true;
});
The only place in a calculator app I can think of where a developer might be tempted to use eval() would be to run it's actual calculations. It's sort of a cheat to just feed an entire mathematical expression to eval() rather than construct a proper parser. I suppose it works (for now) but it's a bad practice.
I built a little calculator app you are welcome to study that performs all the key operations one expects a calculator to do without touching eval(). Feel free to check it out: https://calc-work.webflow.io.
Hope you find this helpful. Cheers!

Related

How to avoid using JavaScript eval() in user-defined function

I'm trying to make a generic table-top RPG helper web app. It has to be generic because Wizards of the Coast is very protective of their copyrights. So, in order to avoid cease-and-desists, the system has to be capable of loading arbitrary rules. That said, my buddies and I (along with most any other user) will be using it for D&D.
In D&D, modifiers are based on a character's stats. To get a modifier, you take the stat, subtract 10, divide by 2, and round down.
function getModifier(statValue) {
return Math.floor((statValue - 10) / 2);
}
My app will be capable to loading a game's rules from a .json file. I want to be able to make this modifier function user-definable. The easiest way would be to just eval() whatever they provide in the .json file, but obviously that's a terrible idea due to security issues.
Unfortunately, I can't think of a simple way to get around this in a secure manner. Obviously I could write my own parser, but that's more complicated than I'd like/am currently capable of.
Ideas?
I did a quick google search and found two options - http://mathjs.org and http://jsep.from.so
btw. writing your own parser is not that difficult. You may be able to write one that's sufficient for your purpose in less than 100 lines of code
First, bear in mind that this is all on the client-side. So long as you trust the JSON (it came from your server or it is controlled alongside the application itself), then you can use it. That doesn't completely rule out some trojan inserting malicious rules, but I don't think botnets have learned to play D&D yet.
To literally avoid eval and provide some modicum of security, you can use new Function. It takes a list of argument names followed by the function body, allowing you a large amount of control over how the function is defined and where it can be referenced from. You only need to store the body in the JSON file, allowing you to largely control the parameters and make it difficult to assign to the global scope, minimizing your attack surface (such as it is) quite a lot.
If you want to have fun with this and now your rules will largely be mathematical, you may consider using a tool like pegjs to generate a parser for your rules. Calculators are one of the classic introductions to parsers and compilers, so this could be an opportunity to play with some fun tech. The rules and parsers built by pegjs are very easy to use in a JS project (I have an example using PegJS and ES6 via Babel).
There are two options as I see it. One, if you 100% want to define the function in .json, you will need to parse. JSON does not allow functions, so you need to store the function as a string and eval it.
The better way would be to also provide a config.js ability. Perhaps the .json would have a "configUrl": property, and then expose well known apis, eg RPGHelper.setModifer(someFunction) that you can call from inside the config.js file. The user is then free to define whatever arbitrary logic there.
One solution to your problem is to use sandboxed iframes (current supported by all major browsers
You run user code on a separate page, with limited priviliges, in such a way that the code does not interfere with the rest of the application. You can communicate with the sandboxed page using postMessage() and window.onmessage.

Eval() vs Developer Tools

So the age old standard is that using Eval is bad because it can cause major security issues; especially in scenarios where you are evaluating something that potentially came from user input somewhere down the line. This makes 100% sense, and I have never had any problem avoiding the use of Eval. I was facing an odd situation recently, though, that sort of made me think about this type of thing a bit differently.
I wrote a JS function sort of like:
function someFun(param, callback) {
bool = someOtherFun(param);
if(bool)
callback();
else
return false;
}
This is much stripped down, but the principal is the same: it calls another function and based on the return value of that will either execute a function provided as a parameter or it will return false. It made me think, though, that this sort of thing could be exploited just as easily as Eval(txtbox.value) with the use of the JS console in F12. Does that matter?
In this world of F12, it seems to me like Eval is the least of our worries. Anyone who knows what an injection attack is is likely to know what F12 is as well. Am I wrong?
While you are correct that tools like F12 and firebug expose your JavaScript to a new level of scrutiny and make it easy for people to attack, you are missing the danger of using eval.
Instead of worrying what a the current user (with the page loaded in the browser might do) lets concern our selves with their co-worked at the next computer. Suppose that co-worker types a comment on Stack Overflow, which is then stored in a database, and then sent out to our user's computer to be displayed. And lets suppose that as part of that rendering process that comment is encoded into JSON and then eval is called on it.
This is where there is a dangerous exploit waiting that has nothing to do with our user inspecting or executing their own JavaScript on the page. If their co-worker embedded malicious JavaScript in their comment and we call eval on it, that JavaScript may be executed causing that malicious code to run on every computer that views the page.
That is why we should avoid using eval.
I don't see the exploit scenario. Yes, they could call your function passing a malicious callback. Or... they could just call the malicious callback from the Console.

Why am I finding Javascript/jQuery so difficult to get right?

My background is in C and I've picked up PHP, mySQL, HTML, CSS without too much issue.
But I'm finding Javascript/jQuery surprisingly difficult to get right.
Very frustrating.
Why?
It seems to violate a number of traditional programming principles (e.g. variable scope)
Undefined variables seem to appear out of nowhere and already have values associated with them. For example (from the jQuery docs):
$("a").click(function(event) {
event.preventDefault();
$('<div/>')
.append('default ' + event.type + ' prevented')
.appendTo('#log');
});
What exactly is "event"? Do I have to use this variable name? Should I just assume that this object is magically instantiated with the right stuff and I can use any of the methods list at the JQuery API?
There seems to be bunch of random rules (e.g. return false to stop a default action, but sometimes this doesn't work?)
Non-deterministic behavior when debugging. (e.g. I refresh the browser, try something and get result X for JS variables I'm watching in Firebug. I refresh again and I get result Y?)
Very messy looking code that is hard to follow. What happens when? I'm using Firebug and Chrome Developer Tools, but I'm not getting enough visibility.
It seems like everyday there's some random JS "rule" that comes up that I've never seen before in any of my JS books or tutorials.
What do I need to do to make Javascript/jQuery more deterministic, controlled, and logical to me?
Are there any resources that explain Javascript's quirks/gotchas?
Thanks!
1) It seems to violate a number of traditional programming principles (e.g. variable scope)
You need to declare variables using var, else it will go into the global scope.
2) Undefined variables seem to appear out of nowhere and already have values associated with them (how did this happen?)
This is possibly related to 1) and/or 4).
3) There seems to be bunch of random rules (e.g. return false to stop a default action, but sometimes this doesn't work?)
You need to let the handler return false as well. E.g. form onsubmit="return functionname()". You also need to return from the "main" function, not only from a closure (a function inside a function), referring to your previous question. It would only return into the "main" function and continue on.
4) Non-deterministic behavior when debugging. (e.g. I refresh the browser, try something and get result X for JS variables I'm watching in Firebug. I refresh again and I get result Y?)
Probably the code was executed before the HTML DOM was finished populating. You need to hook on window.onload or $(document).ready() whenever you want to execute stuff during page load.
5) Very messy looking code that is hard to follow. What happens when? I'm using Firebug and Chrome Developer Tools, but I'm not getting enough visibility.
I bet that you're talking about jQuery source? It's just a large library. You should after all not worry about this when debugging. Rather worry about your own code. However, make sure that you're looking at the unminified version of jQuery's source code.
See also:
JavaScript: the bad parts
What should every JavaScript programmer know
Douglas Crockford's "Javascript: The Good Parts" was an invaluable resource. Javascript plays a lot more like Lua, Lisp, or Python than C, it just happens to LOOK like C.
Link provided to Amazon; I snagged mine from O'Reilly.
To be honest, I think you have a good understanding. Some of my hangups were similar. The way that I have been moving on is "well, if that's the way it is, then that's the way it is". Just accept the idiosyncrasies and plow forward. PHP does some of the same things (variables can show up out of nowhere, etc...). Just code the way you want to code and if it works, then great!
Then after you get to that point start breaking out the profiler and see if there's anything that you can optimize.
Here are a couple of things:
If you understand CSS, then jQuery selectors should be easy. As far as the code goes, that's straightforward too if you can deal with chaining and JSON. EDIT: also, the jQuery documentation on everything is EXCELLENT! And There is no shortage of jQuery experts here on SO to help us noobs (and hopefully we can return the favor for newer noobs).
There is a scope to work with. (Basically) anything written outside of a function or object is in global scope. If you are inside of an object or function and use var then that sets the variable's scope
Javascript isn't like a C-based language (C++ or PHP even). It uses prototypes to deal with class/object relationships rather than a subclassing scheme.
The #1 thing that threw me for a loop is that any JS that appears anywhere on the page or that was included in <script> tags is fair game. If you have a global variable in one script, you can use that same variable in a completely different script and it will work. That may be what you mean about variables showing up out of nowhere. Also, there are some DOM based variables that can just "show up" too.
Anyways, I think that if you just plow ahead, you'll get some "AHA" moments. I'm a relative noob to programming, but I continually grow as long as I don't hang up on something that doesn't have too much of an impact on actually making the code run.
It's a language based on prototypal inheritance and is influenced by functional programming languages and the paradigm so it isn't completely just OO/Procedural like other languages. Variables are implied globals unless declared with var.
Please include an example?
return false exits out of the function as with any language's return statement. preventDefault() would be the DOM method to cancel the default behaviour of a link
Javascript is used primarily on the client side. Since there are many user agents, each of them have a different implementation of the DOM, which is very inconsistent, moreso than JS itself. Again, please include a real example to get a definitive answer.
You'll find messy looking code in any language, and maybe your lack of understanding perceives the code as messy, when in fact it isn't so bad. Or maybe you're looking at some minified/obfuscated code.
I recommend http://eloquentjavascript.net/ for learning aspects of Javascript.
Things you'll learn from the link above
lambdas
closures
Prototypal inheritance
Event based programming
Debugging
DOM
"JavaScript: The Good Parts" by Douglas Crockford is a good start
In your case, the appendices ("the bad parts" and "the awful parts") might be the most interesting :)
Crockford's "Javascript: The Good Parts" gives some common JS patterns that help with variable privatization and scoping. This is for javascript in general. For jQuery I just use the API. Also the Yui Theatre videos on javascript are quite good
Javascript can be a little tricky and some of it's functional aspects confuses people. If you actually learn and understand the language you'll find it really useful, most people just randomly start using it and then just hate.
Read javascript the good parts by crockford, it's really helpful: http://javascript.crockford.com/
Also make sure you understand closure. It's a fundamental that people don't get but often use.
In terms of variable scope, there are local and global variables. One of the gotchyas of variable scope can be seen in this example:
var thisIsAGlobalVariable
function anon () {
var thisIsALocalVariable
thisIsAGlobalVariable = 5; //if you don't use the var prefix inside a fn, it becomes global
}
You are finding it difficult because:
javascript has another kind of syntax.
javascript is dificult to debug
javascript has no autocompletion like c# etc) ?or does it
javascript has illogical rules (they become logical once you are known with them)
everything can be done in 1000 ways, and when you search for a solution, you will find 2000 answers :) where c#, php mostly have a good practice function u "should/could" use
However, I started using js/jquery a half year ago, with the same reasoning as you do, and I stuck to it, and now I use it daily to enhance my webapps.
I just love it (especcially jquery). It is a life saver, I know what and where to look, I can do about anything with it.
Everything seems logical.
If I can give you one advice: javascript/jquery is a sour apple, but just hang in there, bit trough and you won't regret it.
also, a loooot of people use it and are always willing to lend a hand if needed (I know I do)
Javascript is tricky. You don't have a compiler watching your back. To compensate, unit testing becomes more important. I've been doing my unit testing with jQuery/QUnit, but I recently started using Jasmine (http://github.com/pivotal/jasmine) and I recommend it 200%. Its a great testing framework.
If you're not familiar with testing, or testing with javascript, I'd highly recommend finding unit tests for other OSS javascript projects (hopefully for code you could use) and seeing how they test it.
With unit tests, you'll make the same mistakes, but catch them much sooner and with less grief. And if your tests are good, the mistakes won't come back after you fix tham.
I don't know how much UI design you have done in C, but the event variable only shows up when it is sent by the caller and the handler needs to, well, handle the object. If you do reading on event object, the confusion in q #2 should go away.
There is no event handling in PHP, so I think you have not came across this issue in the past. JavaScript is a programming language with its own purpose, so it was designed to work for that specific purpose.
Maybe you have to link your code to an HTML onclick="event()" button to fire off as the event.

intercepting javascript alert()..? is it acceptable?

I just found we can intercept the javascript alert() native call and hook the user code before the actual execution. check out the sample code..
function Test(){
var alertHook=function(aa){
this.alert(aa);
}
this.alert("aa");
this.alert = alertHook;
alert("aa");
}
so everytime i call alert("aa") is been intercepted by my alertHook local function. But the below implementation with the small change does not work.
function Test(){
var alertHook=function(aa){
alert(aa);
}
alert("aa");
alert = alertHook; //throws Microsoft JScript runtime error: Object doesn't support this action
alert("aa");
}
it throws Microsoft JScript runtime error: Object doesn't support this action.
I dont know how this.alert = alertHook; let me intercept the call, but alert=alertHook; not.??
So i assume using this to intercept any native js methods.? is that right?
And is that acceptable? because this way i can completely replacing any native JS calls with my own methods??
UPDATE:
I asked is that acceptable? because how this is a good approach having eval() and letting users to replace native function calls?
And its responsibility of a language to protect developers from the misleading features, replacing the native js calls in a window level(or in a common framework js file) would crash the whole system.. isn't it??
i may be wrong in my opinion because i dont understand the reason behind this feature..? I never seen a language that let developer to replace its own implementation..
Depending on how Test(); is being called, this should be the window Object.
I believe Microsoft allows overwriting native JS functions only by specifying the window object.
So window.alert = alertHook; should work anywhere.
is it acceptable?
Yes it is. This is a major strength for the flexibility of the language, although I'm sure there's better alternatives instead of overwriting native behavior.
Overwriting native JavaScript functions isn't really a security issue. It could be one if you're running someone elses code that does it; but if you're running someone elses code there's a lot of other security issues you should be concerned about.
In my opinion, it never is good practice to redefine the native functions. It's rather better to use wrappers (for instance, create a debug function that directs its output to alert or console.log or ignores the calls or whatever suits your needs).
As for why JScript throws an exception with your second example and not the first one, it's easy. In the first example, you create a property called alert in your local scope, so when you refer alert you'll be referring this.alert rather than window.alert. In the second example, the alert you're referencing is the one from window, so assigning a different function to it will fail.
And its responsibility of a language to protect developers from the misleading features, replacing the native js calls in a window level(or in a common framework js file) would crash the whole system.. isn't it??
Not true, replacing the native call only hooks into it, replaces it: it does not rewrite the native at all. Crashing the "whole" system; JavaScript runs in a Virtual Machine, it's interpreted, so the chance of crashing the "whole" system (i.e. Blue Screen of Death?) is very very small. If so: it's not the programmers fault, but the implementation of JavaScript which is causing the error.
You can consider it as a feature: for instance, if you load a JavaScript from someone else's hand, you can reimplement some functions to extend.
Protection to the programmer is like keeping a dog on the leash: only unleash it, when you trust the dog! Since JavaScript runs in a Virtual Machine, any programmer can be unleashed -- if the implementation is secure enough, which it is (most of the time?)

Why is using the JavaScript eval function a bad idea?

The eval function is a powerful and easy way to dynamically generate code, so what are the caveats?
Improper use of eval opens up your
code for injection attacks
Debugging can be more challenging
(no line numbers, etc.)
eval'd code executes slower (no opportunity to compile/cache eval'd code)
Edit: As #Jeff Walden points out in comments, #3 is less true today than it was in 2008. However, while some caching of compiled scripts may happen this will only be limited to scripts that are eval'd repeated with no modification. A more likely scenario is that you are eval'ing scripts that have undergone slight modification each time and as such could not be cached. Let's just say that SOME eval'd code executes more slowly.
eval isn't always evil. There are times where it's perfectly appropriate.
However, eval is currently and historically massively over-used by people who don't know what they're doing. That includes people writing JavaScript tutorials, unfortunately, and in some cases this can indeed have security consequences - or, more often, simple bugs. So the more we can do to throw a question mark over eval, the better. Any time you use eval you need to sanity-check what you're doing, because chances are you could be doing it a better, safer, cleaner way.
To give an all-too-typical example, to set the colour of an element with an id stored in the variable 'potato':
eval('document.' + potato + '.style.color = "red"');
If the authors of the kind of code above had a clue about the basics of how JavaScript objects work, they'd have realised that square brackets can be used instead of literal dot-names, obviating the need for eval:
document[potato].style.color = 'red';
...which is much easier to read as well as less potentially buggy.
(But then, someone who /really/ knew what they were doing would say:
document.getElementById(potato).style.color = 'red';
which is more reliable than the dodgy old trick of accessing DOM elements straight out of the document object.)
I believe it's because it can execute any JavaScript function from a string. Using it makes it easier for people to inject rogue code into the application.
It's generally only an issue if you're passing eval user input.
Two points come to mind:
Security (but as long as you generate the string to be evaluated yourself, this might be a non-issue)
Performance: until the code to be executed is unknown, it cannot be optimized. (about javascript and performance, certainly Steve Yegge's presentation)
Passing user input to eval() is a security risk, but also each invocation of eval() creates a new instance of the JavaScript interpreter. This can be a resource hog.
Mainly, it's a lot harder to maintain and debug. It's like a goto. You can use it, but it makes it harder to find problems and harder on the people who may need to make changes later.
One thing to keep in mind is that you can often use eval() to execute code in an otherwise restricted environment - social networking sites that block specific JavaScript functions can sometimes be fooled by breaking them up in an eval block -
eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');
So if you're looking to run some JavaScript code where it might not otherwise be allowed (Myspace, I'm looking at you...) then eval() can be a useful trick.
However, for all the reasons mentioned above, you shouldn't use it for your own code, where you have complete control - it's just not necessary, and better-off relegated to the 'tricky JavaScript hacks' shelf.
Unless you let eval() a dynamic content (through cgi or input), it is as safe and solid as all other JavaScript in your page.
Along with the rest of the answers, I don't think eval statements can have advanced minimization.
It is a possible security risk, it has a different scope of execution, and is quite inefficient, as it creates an entirely new scripting environment for the execution of the code. See here for some more info: eval.
It is quite useful, though, and used with moderation can add a lot of good functionality.
Unless you are 100% sure that the code being evaluated is from a trusted source (usually your own application) then it's a surefire way of exposing your system to a cross-site scripting attack.
It's not necessarily that bad provided you know what context you're using it in.
If your application is using eval() to create an object from some JSON which has come back from an XMLHttpRequest to your own site, created by your trusted server-side code, it's probably not a problem.
Untrusted client-side JavaScript code can't do that much anyway. Provided the thing you're executing eval() on has come from a reasonable source, you're fine.
It greatly reduces your level of confidence about security.
If you want the user to input some logical functions and evaluate for AND the OR then the JavaScript eval function is perfect. I can accept two strings and eval(uate) string1 === string2, etc.
If you spot the use of eval() in your code, remember the mantra “eval() is evil.”
This
function takes an arbitrary string and executes it as JavaScript code. When the code in
question is known beforehand (not determined at runtime), there’s no reason to use
eval().
If the code is dynamically generated at runtime, there’s often a better way to
achieve the goal without eval().
For example, just using square bracket notation to
access dynamic properties is better and simpler:
// antipattern
var property = "name";
alert(eval("obj." + property));
// preferred
var property = "name";
alert(obj[property]);
Using eval() also has security implications, because you might be executing code (for
example coming from the network) that has been tampered with.
This is a common antipattern when dealing with a JSON response from an Ajax request.
In those cases
it’s better to use the browsers’ built-in methods to parse the JSON response to make
sure it’s safe and valid. For browsers that don’t support JSON.parse() natively, you can
use a library from JSON.org.
It’s also important to remember that passing strings to setInterval(), setTimeout(),
and the Function() constructor is, for the most part, similar to using eval() and therefore
should be avoided.
Behind the scenes, JavaScript still has to evaluate and execute
the string you pass as programming code:
// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);
// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);
Using the new Function() constructor is similar to eval() and should be approached
with care. It could be a powerful construct but is often misused.
If you absolutely must
use eval(), you can consider using new Function() instead.
There is a small potential
benefit because the code evaluated in new Function() will be running in a local function
scope, so any variables defined with var in the code being evaluated will not become
globals automatically.
Another way to prevent automatic globals is to wrap the
eval() call into an immediate function.
EDIT: As Benjie's comment suggests, this no longer seems to be the case in chrome v108, it would seem that chrome can now handle garbage collection of evaled scripts.
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
Garbage collection
The browsers garbage collection has no idea if the code that's eval'ed can be removed from memory so it just keeps it stored until the page is reloaded.
Not too bad if your users are only on your page shortly, but it can be a problem for webapp's.
Here's a script to demo the problem
https://jsfiddle.net/CynderRnAsh/qux1osnw/
document.getElementById("evalLeak").onclick = (e) => {
for(let x = 0; x < 100; x++) {
eval(x.toString());
}
};
Something as simple as the above code causes a small amount of memory to be store until the app dies.
This is worse when the evaled script is a giant function, and called on interval.
Besides the possible security issues if you are executing user-submitted code, most of the time there's a better way that doesn't involve re-parsing the code every time it's executed. Anonymous functions or object properties can replace most uses of eval and are much safer and faster.
This may become more of an issue as the next generation of browsers come out with some flavor of a JavaScript compiler. Code executed via Eval may not perform as well as the rest of your JavaScript against these newer browsers. Someone should do some profiling.
This is one of good articles talking about eval and how it is not an evil:
http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/
I’m not saying you should go run out and start using eval()
everywhere. In fact, there are very few good use cases for running
eval() at all. There are definitely concerns with code clarity,
debugability, and certainly performance that should not be overlooked.
But you shouldn’t be afraid to use it when you have a case where
eval() makes sense. Try not using it first, but don’t let anyone scare
you into thinking your code is more fragile or less secure when eval()
is used appropriately.
eval() is very powerful and can be used to execute a JS statement or evaluate an expression. But the question isn't about the uses of eval() but lets just say some how the string you running with eval() is affected by a malicious party. At the end you will be running malicious code. With power comes great responsibility. So use it wisely is you are using it.
This isn't related much to eval() function but this article has pretty good information:
http://blogs.popart.com/2009/07/javascript-injection-attacks/
If you are looking for the basics of eval() look here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
The JavaScript Engine has a number of performance optimizations that it performs during the compilation phase. Some of these boil down to being able to essentially statically analyze the code as it lexes, and pre-determine where all the variable and function declarations are, so that it takes less effort to resolve identifiers during execution.
But if the Engine finds an eval(..) in the code, it essentially has to assume that all its awareness of identifier location may be invalid, because it cannot know at lexing time exactly what code you may pass to eval(..) to modify the lexical scope, or the contents of the object you may pass to with to create a new lexical scope to be consulted.
In other words, in the pessimistic sense, most of those optimizations it would make are pointless if eval(..) is present, so it simply doesn't perform the optimizations at all.
This explains it all.
Reference :
https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval
https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance
It's not always a bad idea. Take for example, code generation. I recently wrote a library called Hyperbars which bridges the gap between virtual-dom and handlebars. It does this by parsing a handlebars template and converting it to hyperscript which is subsequently used by virtual-dom. The hyperscript is generated as a string first and before returning it, eval() it to turn it into executable code. I have found eval() in this particular situation the exact opposite of evil.
Basically from
<div>
{{#each names}}
<span>{{this}}</span>
{{/each}}
</div>
To this
(function (state) {
var Runtime = Hyperbars.Runtime;
var context = state;
return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
return [h('span', {}, [options['#index'], context])]
})])
}.bind({}))
The performance of eval() isn't an issue in a situation like this because you only need to interpret the generated string once and then reuse the executable output many times over.
You can see how the code generation was achieved if you're curious here.
I would go as far as to say that it doesn't really matter if you use eval() in javascript which is run in browsers.*(caveat)
All modern browsers have a developer console where you can execute arbitrary javascript anyway and any semi-smart developer can look at your JS source and put whatever bits of it they need to into the dev console to do what they wish.
*As long as your server endpoints have the correct validation & sanitisation of user supplied values, it should not matter what gets parsed and eval'd in your client side javascript.
If you were to ask if it's suitable to use eval() in PHP however, the answer is NO, unless you whitelist any values which may be passed to your eval statement.
I won't attempt to refute anything said heretofore, but i will offer this use of eval() that (as far as I know) can't be done any other way. There's probably other ways to code this, and probably ways to optimize it, but this is done longhand and without any bells and whistles for clarity sake to illustrate a use of eval that really doesn't have any other alternatives. That is: dynamical (or more accurately) programmically-created object names (as opposed to values).
//Place this in a common/global JS lib:
var NS = function(namespace){
var namespaceParts = String(namespace).split(".");
var namespaceToTest = "";
for(var i = 0; i < namespaceParts.length; i++){
if(i === 0){
namespaceToTest = namespaceParts[i];
}
else{
namespaceToTest = namespaceToTest + "." + namespaceParts[i];
}
if(eval('typeof ' + namespaceToTest) === "undefined"){
eval(namespaceToTest + ' = {}');
}
}
return eval(namespace);
}
//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
//Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
//Code goes here
//this.MyOtherMethod("foo")); // => "foo"
return true;
}
//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);
EDIT: by the way, I wouldn't suggest (for all the security reasons pointed out heretofore) that you base you object names on user input. I can't imagine any good reason you'd want to do that though. Still, thought I'd point it out that it wouldn't be a good idea :)

Categories

Resources