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";
}Recommended Modern Alternatives
Object Destructuring: Extract properties explicitly to work with them locally:
const { name, age } = user; console.log(name, age);Temporary References: Assign the object to a short variable name:
const u = user; u.name = "Jordan"; u.age = 31;Object Methods: Encapsulate operations within methods on the object itself to handle internal mutations cleanly.