JavaScript With Statement: Usage and Deprecation Reasons

The with statement in JavaScript was originally designed to provide a shorthand syntax for modifying properties on a specific object. However, due to its negative impact on runtime performance, lexical scope predictability, and security, it has been officially deprecated and forbidden in ECMAScript strict mode. This article explains how the with statement functions, the technical problems it introduces, and the modern alternatives developers should use instead.

How the with Statement Works

The with statement temporarily extends the scope chain for a block of code by placing a specified object at the top of that chain. Any unqualified variable lookup inside the block first evaluates whether the property exists on the specified object before searching the surrounding lexical scopes.

The syntax is structured as follows:

with (expression) {
    statement;
}

For example, consider modifying an object without with:

const user = {
    name: "Alex",
    age: 30,
    role: "Admin"
};

// Standard access
user.name = "Jordan";
user.age = 31;

Using the with statement, the object name can be omitted within the block:

with (user) {
    name = "Jordan";
    age = 31;
}

During execution, JavaScript treats name and age as user.name and user.age because those properties exist on the user object.

Why the with Statement Is Deprecated

Despite its apparent convenience, the with statement introduces severe issues into the JavaScript runtime environment.

1. Scope Ambiguity and Unintended Side Effects

The with statement makes code unpredictable because variable resolution depends entirely on the runtime state of the object rather than lexical scope. If a property is missing from the target object, the lookup traverses up to the outer scope, potentially overwriting unintended variables.

function updateData(obj, value) {
    with (obj) {
        data = value; // If 'obj.data' does not exist, this modifies an outer 'data' variable or creates a global variable.
    }
}

If properties are dynamically added, removed, or inherited via prototypes at runtime, the behavior of the code within the with block can unpredictably change.

2. Performance De-optimization

Modern JavaScript engines use Just-In-Time (JIT) compilation to optimize variable lookups ahead of execution. The engine maps variable references to fixed memory locations based on static lexical scope.

Because with introduces dynamic scope resolution that can only be determined at runtime, the JavaScript engine must disable critical optimizations (such as inline caching and lexical variable flattening). This causes significant performance degradation not only within the with block but often across the containing function.

3. Security and Debugging Difficulties

The dynamic nature of with makes static analysis tools, linters, and human readers unable to verify where a variable originates without executing the code. This obfuscation increases the risk of subtle bugs, prototype pollution vulnerabilities, and errors during code minification.

Strict Mode and Modern Alternatives

In ECMAScript 5, strict mode ("use strict";) introduced a syntax error whenever the with keyword is encountered:

"use strict";
with (user) { // SyntaxError: Strict mode code may not include a with statement
    name = "Jordan";
}
  1. Object Destructuring: Extract properties explicitly to work with them locally:

    const { name, age } = user;
    console.log(name, age);
  2. Temporary References: Assign the object to a short variable name:

    const u = user;
    u.name = "Jordan";
    u.age = 31;
  3. Object Methods: Encapsulate operations within methods on the object itself to handle internal mutations cleanly.