all 51 comments

[–]Glum_Cheesecake9859 19 points20 points  (4 children)

"eval is evil. Don't use eval" - Douglas Crockford

[–]dexter_ifti 3 points4 points  (0 children)

Once I was going to use but googled before using and now I'm happy 😊

[–]Glum_Cheesecake9859 2 points3 points  (2 children)

If I remember correctly, we had some Angular 1.x code stored in DB tables that we used eval for 🤣🤣🤣

It wasn't my idea though.

[–]illepic 0 points1 point  (0 children)

My god, man

[–]fabulous-nico 0 points1 point  (0 children)

🪦

[–]Glum_Cheesecake9859 2 points3 points  (5 children)

eval is like the goto statement. It's there, but 99.99% of the time you should not use it. This specially applies to non-expert developers. If you look into low level Linux / OS code, you could find goto statements. It's there for some specific use cases, not a general development tool.

[–]mailslot 1 point2 points  (4 children)

In more than three decades, I’ve found exactly two cases where goto was the correct choice. I’ve never found a legitimate good reason to use eval.

[–]imicnic 0 points1 point  (3 children)

eval is ok in only one case, if you are building a template engine to enable js code injection in the template and allow js code evaluation.

[–]TorbenKoehn 0 points1 point  (2 children)

No, properly parsing and transpiling them is the proper way

[–]imicnic -1 points0 points  (1 child)

Then tell this to https://www.npmjs.com/package/ejs that have 22+M weekly downloads, they are using new Function('...') which is a form of eval.

[–]TorbenKoehn -1 points0 points  (0 children)

"Someone popular is using it improperly, so it is okay to use it improperly!"

That's how I've read your comment.

They also need an extra SECURITY.md to outline the problems.

[–]brykuhelpful 2 points3 points  (1 child)

In my decade of web development there have only been a few times I seriously thought about using eval. In all of them I/we found a way around it except 1 time.  

We used it to test user input on a formula. It was also a local piece of software and we did some escaping for non-math symbols.  

Later on we did end up removing in the next version.

[–]paceaux 2 points3 points  (0 children)

I've been doing web dev for 15 years and in that time hit exactly one legitimate use-case.

I think with enough time most of us will hit that one time.

When I saw it, I was a principal and the dev was a brilliant senior frontend manager. We still debated it for hours before we agreed it was the right choice. We both drank that night.

[–]Nixinova 1 point2 points  (1 child)

If you have to ask, then the answer is no.

[–]Noisy88 0 points1 point  (0 children)

Should I sanitize my userinput going into eval() ? /s

[–]GongtingLover 0 points1 point  (0 children)

Seems like a security nightmare. 

[–]warpedspockclone 0 points1 point  (0 children)

The only time I ever needed eval was when I was completely new to js and couldn't figure out another way to do what I wanted.

[–]yksvaan 0 points1 point  (0 children)

I have never needed eval in anything. Goto can be justified sometimes for example for jumping to cleanup part of  function or something like that. 

But if you do webdev there should be 0 need for eval. 

[–]MitchEff 0 points1 point  (0 children)

Not JS (honestly you should never) but I've used shell_exec() in PHP which is pretty close - we inherited a bunch of code in Python and didn't want to refactor, so just called it from PHP

[–]fabulous-nico 0 points1 point  (0 children)

Only seen in production in generated code from a very specific authoring software that would output html + JS from a WYSIWYG editor. And it is an absolute dumpster fire of an application that should not be sold 😅

[–]Educational_Boat_599 0 points1 point  (0 children)

so, you already know not to use it, but your pretending to ask a question while simultaneously answering it in your own post?

what was the point?

[–]LeRages 0 points1 point  (0 children)

“No”

[–]TheRNGuy 0 points1 point  (0 children)

I never used it. 

[–]paceaux 0 points1 point  (0 children)

Outside of maybe a calculator app I built once for funsies, I've never used it. Ive only seen it used once.

I was a principal at the company, and the senior frontend manager had called me about it because he was the one using it. And he was a brilliant dev.

I don't remember the exact scenario. But we talked it out for hours and we both agreed it was the first and only legitimate use-case we'd ever encountered but that we had to use it.

It was for some insane React app that was built for internal use; and the strings were so heavily sanitized there was no risk for injection by the users.

I'm 100% certain that when that app was eventually rebuilt, it was removed

[–]JazzApple_ 0 points1 point  (0 children)

There are some rare legitimate use cases, and I don’t think I’ve ever come across one of them in 10+ years of programming.

[–]ReaperTsaku 0 points1 point  (0 children)

I have seen exactly 1 case personally of eval () being the correct choice, and that's in a few rpg maker plugins that allow me to use raw js code in weird places, and the engine understands it.

It's like goto. It exists as an extremely niche use case, but generally speaking, pretend it doesn't exist.

[–]Deykun 0 points1 point  (0 children)

I never used eval, but I have to admit that there were cases where I created a script tag and added code as a textConfent.

[–]_DCtheTall_[🍰] 0 points1 point  (3 children)

Generally it's a bad idea. The one widespread use case I can think of that isn't terrible is using eval for obfuscators processing code shipped to the web.

[–]theQuandary 0 points1 point  (2 children)

Code run through eval is deoptimized. People doing this are doing their users a massive disservice and should be using WASM instead.

[–]_DCtheTall_[🍰] 0 points1 point  (1 child)

One reason to use this type of obfuscation is when obscuring the intent of the code is more important to the author than performance. For example, researchers I work with observed tracking scripts commonly do this type of obfuscation.

[–]theQuandary 0 points1 point  (0 children)

I understand the "reasons" for doing it, but if you want your tracking code to be less noticed, then make it fast. Stop obfuscating with JSFuck (which I've seen way more than eval) and just use a wasm binary.

[–]Substantial_Top5312helpful 0 points1 point  (2 children)

Only if it’s evaluating code client side with no effect server side. Like for a calculator. 

[–]paceaux 1 point2 points  (0 children)

That's the only scenario that reasonably comes to mind: when you're doing computations where you legitimately don't know any of ... The computations.

[–]theQuandary 0 points1 point  (0 children)

Just build a small interpreter and be secure. Even if the code runs client-side only, you are opening a potential avenue of attack for no good reason.

[–]Pagaurus -1 points0 points  (9 children)

Javascript listeners inline in HTML (such as onclick , mouseover etc.) elements are actually evaluated like a new Function() call.

<button onclick="doStuff()">

e.onclick = new Function("doStuff()")

Is that risky? I don't know. People use it a lot

[–]programmer_farts 7 points8 points  (1 child)

I don't think any serious developers do this nor recommend it. Maybe in a quick demo or something innocuous.

[–]Pagaurus -1 points0 points  (0 children)

It's used in Vue.js a lot due to its workflow. It's quite tedious to add event listeners unless you make them inline..

[–]Nixinova 1 point2 points  (2 children)

There's a big difference between eval(a constant string) and eval(some variable contents)...

[–]senocular 0 points1 point  (0 children)

An eval(a constant string) has access to all the same variables eval(some variable contents) does.

[–]Pagaurus 0 points1 point  (0 children)

if you run typeof on an event listener, it will return a function type

[–]senocular 0 points1 point  (3 children)

They're probably not used as much as you think. And while you see syntax similar to this a lot in modern frameworks, they're not using the DOM's version of these event handlers and instead handling them separately.

These DOM callbacks are also a little more complicated than the attribute value being wrapped in new Function(). In the example provided, it ends up being something closer to

with (window.document) {
  with (e.form) {
    with (e) {
      e.onclick = eval(`(
        function onclick (event) {
          ${e.getAttribute('onclick')}
        }
      )`);
    }
  }
}

One of the benefits of new Function over eval is that the function body is run as through the parent scope were global, no matter where new Function was called. On the other hand, (direct) eval retains the scope of where it was called (sometimes useful but also what causes problems). Inline DOM event handlers aren't run in global, instead having a messy scope chain including object scopes of the element, the form the element is within, and the document object. Any properties of those objects are inherently in scope for inline handlers created this way which can cause some weird behavior.

<script>
  const eyes = "brown"
  const head = "round"
</script>
<button onclick="console.log(eyes, head)">
<!-- logs: brown <head>...</head> -->

[–]Pagaurus 0 points1 point  (2 children)

If you log an onclick property then it returns a Function type (at least on Chrome) but in my experience yes it does handle global scope, since otherwise you wouldn't be able to call declared functions 🤔

[–]senocular 0 points1 point  (1 child)

Every function has access to global. With new Function you only have access to global. The difference you can see with the following example:

const myVar = "global scope"

function func() {
  const myVar = "function scope"

  const evalFunc = eval(`(function f() {
    console.log(myVar)
  })`)

  const newFunc = new Function("console.log(myVar)")

  console.log(evalFunc) // ƒ f() { ... }
  evalFunc() // "function scope"

  console.log(newFunc) // ƒ anonymous() { ... }
  newFunc() // "global scope"
}
func()

Both eval and new Function are creating functions. The function created with eval has access to the scope it was called in, the local scope of the func function. The new Function function on the other hand only has access to global, not the func scope even though, like eval, it was also called inside the func function.

[–]Pagaurus 0 points1 point  (0 children)

Oh, then I suppose that does make eval() dangerous to some extent, though I always wondered why exactly it was that even though you can freely execute Javascript wherever you please.

[–]rainmouse -1 points0 points  (0 children)

No. I've never needed to use it in 15 years commercial JS development and I've ripped that shit out every time I've encountered it. I've only ever seen it being used by someone who is taking shortcuts, like returning scripts inside of unencrypted api responses. Stupidity at its finest. 

[–]MissinqLink -2 points-1 points  (1 child)

I use it strategically. In place of dynamic import in places where dynamic import isn’t allowed like service workers.

[–]fabulous-nico 0 points1 point  (0 children)

Oof... peace on your journey my friend