# Why You Should Avoid eval() and with in JavaScript: Lexical Scope Explained

> Learn why eval and with break JavaScripts lexical scope. Avoid these functions to prevent security risks and improve code performance by disabling optimizations.

- Repository: [Kyle Simpson/You-Dont-Know-JS](https://github.com/getify/You-Dont-Know-JS)
- Tags: best-practices
- Published: 2026-02-24

---

**Both `eval()` and the `with` statement violate JavaScript's lexical scope model, forcing engines to disable compile-time optimizations and introducing security vulnerabilities and maintenance nightmares.**

Modern JavaScript engines rely on lexical scope to optimize code at compile time, but two legacy features—`eval()` and `with`—break this contract by modifying scope at runtime. According to the *You Don't Know JS* book series by getify, these constructs force engines to abandon optimizations and create unpredictable execution contexts that make code harder to reason about and secure.

## How eval() Breaks Lexical Scope

### Runtime Scope Modification

In [`scope-closures/ch1.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/ch1.md) (lines 69-79), the book explains that `eval()` parses strings as live code during execution. When that string contains `var` or `function` declarations, it mutates the current lexical environment—the function's scope—at runtime.

Example from the source:

```javascript
function badIdea() {
  eval("var oops = 'Ugh!';");   // creates a new var in this function's scope
  console.log(oops);            // works only because eval added it
}
badIdea(); // → Ugh!

```

### Performance Penalties

Lines 80-88 of the same file note that every `eval()` execution forces the engine to re-parse code and re-enter the compilation pipeline. This nullifies just-in-time optimizations, prevents variable inlining, and can trigger de-optimization and garbage-collection pressure.

### Security Risks

At lines 93-94, the book warns that `eval()` executes arbitrary strings with full access to the surrounding scope and global objects. Any user-controlled input passed to `eval()` becomes first-class JavaScript, creating injection vulnerabilities.

## How the with Statement Creates Dynamic Scope

The `with` statement (lines 81-88 in [`scope-closures/ch1.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/ch1.md)) treats object properties as local variables by injecting a new lexical environment at runtime.

```javascript
var bad = { oops: "Ugh!" };

with (bad) {
  console.log(oops); // oops is looked up in `bad` at runtime
}

```

This prevents static identifier resolution. The engine cannot know at compile time whether `oops` refers to a property of `bad` or an outer variable, forcing runtime lookups that hurt performance and obscure code intent.

## Strict Mode Eliminates Both

As noted in lines 92-94 of [`scope-closures/ch1.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/ch1.md), ES5 strict mode removes these features entirely. `eval()` cannot create declarations, and `with` is a syntax error.

```javascript
"use strict";

function safe() {
  // eval("var x = 1;");   // SyntaxError in strict mode
  // with (obj) {}          // SyntaxError: with statements not allowed
}

```

## Better Alternatives to eval() and with

Instead of `eval()`, use direct property access or the `Function` constructor (though the latter still requires caution). Instead of `with`, use destructuring or explicit object references.

Safe alternative to `eval()`:

```javascript
function betterIdea() {
  const oops = 'Ugh!';
  console.log(oops);
}
betterIdea();

```

Safe alternative to `with`:

```javascript
var bad = { oops: "Ugh!" };
console.log(bad.oops); // explicit property access

```

## Summary

- `eval()` mutates lexical scope at runtime by parsing strings as live code, forcing engines to abandon compile-time optimizations.
- `with` injects object properties as variables, preventing static identifier resolution and hurting performance.
- Both constructs create security vulnerabilities and make code harder to debug and maintain.
- ES5 strict mode prohibits both `eval()` declarations and `with` statements entirely.
- Modern JavaScript provides safer alternatives like explicit property access and destructuring.

## Frequently Asked Questions

### Why is eval() considered dangerous in JavaScript?

`eval()` executes arbitrary code strings with full access to the current scope and global objects. If user input reaches `eval()`, attackers can inject malicious JavaScript that steals data or performs unauthorized actions. Additionally, because `eval()` can introduce new variables at runtime, it prevents JavaScript engines from optimizing the surrounding code.

### Does using with affect JavaScript performance?

Yes, the `with` statement forces the JavaScript engine to perform runtime identifier resolution rather than compile-time resolution. Because the engine cannot determine whether an identifier refers to a property of the `with` object or an outer variable until execution, it must disable optimizations like variable inlining and constant folding. This results in significantly slower execution compared to explicit property access.

### Can I use eval() safely in strict mode?

Strict mode removes some dangers of `eval()` by preventing it from introducing new declarations into the surrounding scope—variables created inside `eval()` remain local to the evaluated code. However, `eval()` still executes arbitrary code and carries security risks if passed untrusted strings. For this reason, even in strict mode, the book recommends avoiding `eval()` entirely in favor of safer alternatives like `JSON.parse()` for data or direct function calls for logic.

### What is the best alternative to the with statement?

The best replacement for `with` is explicit property access using dot notation (`obj.property`) or bracket notation (`obj['property']`). For cases where you need to reference multiple properties of an object repeatedly, use destructuring assignment to create local variables: `const { prop1, prop2 } = obj;`. These approaches maintain lexical scope clarity, allow engine optimizations, and make it obvious which identifiers refer to object properties versus outer variables.