Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The with statement extends the scope chain for a specific block of code by temporarily injecting an object’s properties at the front of the lexical environment. This allows properties of the evaluated object to be referenced as unqualified identifiers within the statement’s body.
with (expression) {
  statement;
}

Mechanics of Identifier Resolution

When the JavaScript engine executes a with statement, it evaluates the expression. If the expression evaluates to null or undefined, the engine cannot cast it to an object and will immediately throw a TypeError. Otherwise, the engine casts the result to an object and pushes it onto the head of the current execution context’s scope chain. During the execution of the statement block, whenever the engine encounters an unqualified identifier, it performs a property lookup on the injected object first.
  • If the property exists on the object and the property key is not masked by the object’s [Symbol.unscopables] list, the identifier binds to that property.
  • If the property does not exist, or if it is explicitly excluded by Symbol.unscopables, the engine ignores the object and traverses up the standard lexical scope chain to resolve the binding.
  • If an assignment is made to an identifier that does not exist on the object and is not found in the scope chain, it does not create a new property on the object; instead, it creates a new global variable (in non-strict mode).
const contextObj = { x: 10, y: 20 };
// Mask 'y' from the with statement's scope chain
contextObj[Symbol.unscopables] = { y: true }; 

let z = 30;
let y = 50;

with (contextObj) {
  x = 100; // Mutates contextObj.x
  y = 200; // Mutates the lexically scoped variable 'y' (contextObj.y is unscopable)
  z = 300; // Mutates the lexically scoped variable 'z'
  w = 400; // Creates a global variable 'w', does NOT mutate contextObj
}

Technical Implications

The Symbol.unscopables Protocol Introduced in ES6, Symbol.unscopables is a mechanism designed specifically to hide certain object properties from the with environment’s scope chain. This was implemented to maintain backward compatibility when new methods were added to built-in prototypes. For example, Array.prototype[Symbol.unscopables] prevents properties like keys, values, and entries from shadowing variables in existing codebases that wrap arrays in a with statement. Strict Mode Prohibition The with statement is entirely forbidden in ECMAScript Strict Mode ("use strict";). Attempting to parse a with statement in a strict mode script or function will throw a SyntaxError during the compilation phase. Performance Degradation Modern JavaScript engines (such as V8, SpiderMonkey, and JavaScriptCore) heavily optimize identifier resolution by analyzing the lexical scope during the compilation phase. The with statement makes static analysis impossible, as the shape and properties of the evaluated object cannot be guaranteed until runtime. Consequently, the engine must disable lexical binding optimizations and fall back to slow, dynamic property lookups for all identifiers within the block. Lexical Ambiguity The statement introduces severe unpredictability into code execution. Because identifier resolution depends entirely on the runtime state of the object, it is impossible to determine statically whether an identifier refers to an object property or an outer-scoped variable. If the object’s prototype chain changes or properties are dynamically added/removed, the binding of identifiers inside the with block will silently change targets.
Master JavaScript with Deep Grasping Methodology!Learn More