19

OBSOLETE

The block version of the let statement was dropped from ES6 before it was finalized, and it has been removed from the browsers that supported it. This question is now only of historic interest.

Is there any difference between using an ECMAScript 6 let block statement and using a with statement with an equivalent object literal?

using let statement

var x = 10;
let (x = x * 10,
     y = x + 5) {
    console.log("x is " + x + ", y is " + y);
}

using with statement

var x = 10;
with ({x: x * 10,
       y: x + 5}) {
    console.log("x is " + x + ", y is " + y);
    // writes "x is 100, y is 15"
}
Jeremy
  • 1
  • 85
  • 340
  • 366
  • 1
    Is the question for entertainment, or are you seriously considering using `with` for scoping? – Ruan Mendes Jun 29 '11 at 01:21
  • 1
    If the answer was conclusively "no difference" then I would consider it, but I was mainly curious because I expected a difference but couldn't find one. – Jeremy Jun 29 '11 at 02:23

3 Answers3

8

You can use both with and let statements to achieve the same goal but I see two significant differences here. In the end, the let statement is a new revision of the with statement with the disadvantages of the latter removed.

Performance: In case of the with statement you add an additional JavaScript object to the scope chain. This isn't a small cost, you have to remember that objects have a potentially long prototype chain and so to look up a variable the JavaScript engine first has to search the object and all its prototypes. On the other hand, for a let statement the engine only needs to search at most one additional object. The let statement can indeed be implemented without any overhead at all, since all the variables declared in a let statement are known at compile time and the JavaScript engine can easily optimize the code, e.g. by essentially treating your example like:

var x = 10;
var let1x = x * 10;
var let1y = x + 5;
{
    console.log("x is " + let1x + ", y is " + let1y);
}

Code readability: As already mentioned above, a let statement always makes all declarations visible at compile time, this prevents code like this:

with (foo)
{
    console.log("x is " + x + ", y is " + y);
}

If you look at the code above, what is x and what is y? Are they function variables or properties of the object foo? You cannot tell it without knowing what foo is - and it might be different for different calls of the same function. Which is the main reason the with statement has been deprecated. While you can use it the way you've done in your question (and that is fine), it also allows very questionable and unreadable code constructs. The let statement doesn't - less flexibility is sometimes an advantage.

Wladimir Palant
  • 56,865
  • 12
  • 98
  • 126
7

The best I can come up with is that with will also leak any property of the Object prototype:

with ({x: 10}) {
    hasOwnProperty = 3;
    console.log(hasOwnProperty);  // 3
}
console.log(hasOwnProperty);  // [native code]; this is window.hasOwnProperty

Unlikely to be a problem in practice, but still a potential gotcha.

I also suspect that with is slightly slower than lexicals, since it adds another namespace that has to be searched.

Honestly, I'd just avoid both constructs; with-style implicit property access doesn't sit well with me, and if I really need a tight scope like that, a bare block with let expressions inside reads less awkwardly than a let block.

Eevee
  • 47,412
  • 11
  • 95
  • 127
  • Note that ECMAScript 5 lets us create an objet with no prototype as `Object.create(null)`, so it actually seems possible to use this with no side-effects. However, ES5's strict mode disables `with`, so this is only possible in ES5's default mode and won't be possible in ES6. – Jeremy Aug 23 '11 at 11:24
  • See [Was there a way to create an object without a prototype prior to ES5?](http://stackoverflow.com/a/36117912/1114) for a possible (though very impractical) alternative for ES3. – Jeremy Mar 22 '16 at 04:04
1

Here are the different scoping rules for each statement.

with:

the with statement makes access to named references inefficient, because the scopes for such access cannot be computed until runtime

let:

The scope of variables defined using let is the let block itself, as well as any inner blocks contained inside it, unless those blocks define variables by the same names.

The let statement is non-standard, while the with statement is unavailable in Strict Mode.

References

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265