64

Possible Duplicate:
Are there legitimate uses for JavaScript’s “with” statement?

I recently discovered that in JavaScript, one can do something like the following:

with (document) {
    write('foo');
    body.scrollTop = x;
}

The down side of this is that each variable needs to be checked to see if it belongs to the document object, creating a significant overhead.

Alternatively, one could do something like this:

var d = document;
d.write('foo');
d.body.scrollTop = x;

Are there any situations where the use of the 'with' keyword is justified?

mic
  • 1,190
  • 1
  • 17
  • 29
John McCollum
  • 5,162
  • 4
  • 34
  • 50
  • 1
    Here are some blog posts in support of the with keyword. But please read the YUI blog entry that azazul posted as well! [http://webreflection.blogspot.com/2009/12/with-worlds-most-misunderstood.html](http://webreflection.blogspot.com/2009/12/with-worlds-most-misunderstood.html) [http://webreflection.blogspot.com/2009/12/with-some-good-example.html](http://webreflection.blogspot.com/2009/12/with-some-good-example.html) – Annie Dec 18 '09 at 23:11
  • @Abel, you're right, this answers my question nicely as well as sticking a giant caveat on there too. – John McCollum Dec 18 '09 at 23:24
  • @Annie: I think you should paste some quotes here instead of simply linking two related articles. What if they lead to a 404 (or similar) HTTP code later (e.g. because these articles were moved/deleted)? – Sk8erPeter Jan 20 '14 at 15:37
  • **Using `with` is not recommended, and is forbidden in ECMAScript 5 strict mode. The recommended alternative is to assign the object whose properties you want to access to a temporary variable.** Source:[Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with) – Pankaj Oct 26 '17 at 07:06

3 Answers3

94

Just don't use it: http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/

JavaScript's with statement was intended to provide a shorthand for writing recurring accesses to objects. So instead of writing

ooo.eee.oo.ah_ah.ting.tang.walla.walla.bing = true;
ooo.eee.oo.ah_ah.ting.tang.walla.walla.bang = true;

You can write

with (ooo.eee.oo.ah_ah.ting.tang.walla.walla) {
    bing = true;
    bang = true;
}

That looks a lot nicer. Except for one thing. There is no way that you can tell by looking at the code which bing and bang will get modifed. Will ooo.eee.oo.ah_ah.ting.tang.walla.walla be modified? Or will the global variables bing and bang get clobbered? It is impossible to know for sure...

If you can't read a program and be confident that you know what it is going to do, you can't have confidence that it is going to work correctly. For this reason, the with statement should be avoided...

gnat
  • 6,213
  • 108
  • 53
  • 73
azazul
  • 1,205
  • 1
  • 7
  • 5
  • 4
    I can't express this enough: any "with"-like syntax, like the one for JavaScript and Delphi, where you're not explicitly specifying which identifiers belong to the "scoped" object, and which one aren't, are **evil**, don't use that syntax in those languages. In particular, future changes might change the behavior of that code without warning. If that isn't a bug just waiting to happen, then I don't know what is. – Lasse V. Karlsen Dec 18 '09 at 23:12
  • 5
    For instance, Visual Basic.NET got it right, http://msdn.microsoft.com/en-us/library/wc500chb(VS.80).aspx, where they force you to prefix all identifiers belonging to the scoped object with a dot. – Lasse V. Karlsen Dec 18 '09 at 23:14
  • Yeah, VB (.NET and before) got it right, but they also got it wrong: if you use late-binding, your still in the same problem. And performance with `with` is slower then without (for whatever odd reason). – Abel Dec 18 '09 at 23:16
  • 2
    @John: the only justification I can find is where code becomes clearer when using it. If you find yourself in such a situation, you can use it... – Abel Dec 18 '09 at 23:17
  • @John (2): about justification, check Annie's answer: http://stackoverflow.com/questions/1931186/with-keyword-in-javascript/1931202#1931202 – Abel Dec 18 '09 at 23:21
  • Pathetically, this is not just a knee-jerk reaction, but a *parroted* knee-jerk reaction. See http://stackoverflow.com/a/19012662/34806 for using with, with requirejs – Dexygen Sep 25 '13 at 18:41
24

Despite advice to the contrary almost everywhere, I think that there are uses for "with". For example, I'm working on a domain model framework for Javascript, which uses the underscore character in much the same way that jQuery uses "$". This means that without "with", I have lots of underscores scattered through my code in ways that make it less readable. Here's a random line from an application using the framework:

_.People().sort(_.score(_.isa(_.Parent)),'Surname','Forename');

whereas with "with" it would look like

with (_) {
    ...

    People().sort(score(isa(Parent)),'Surname','Forename');

    ...
}

What would be really useful is a read-only version of "with".

Rich
  • 3,095
  • 17
  • 17
  • Not always SLOWER runtime give you side effects. Its negligible if you don't run it thousand times. – kroe Jan 29 '14 at 11:55
  • 24
    These days, with ES6 object destructuring, you could instead do `const { People, score, isa, Parent } = _;`, and not bring on all the nasty risks of `with (_)`. – Cam Jackson Nov 05 '16 at 11:18
  • @CamJackson Yes, but people must take note that destructuring clones the value of the property. Therefore, if the value of the property is a primitive, then it will not actually be writing to the original object. This will not affect properties that have values of objects because they are just references to that data: ``` const person = { name: "Harry Potter", }; let { name } = person; name = "Draco Malfoy"; // assigning to the termporary primitive console.log(person.name); // Harry Potter ``` Therefore, it's best practice to prefer using `const { ... } = foo`. – sno2 Mar 14 '21 at 05:36
6

I would avoid using it in production code because it's ambiguous but there is an alternative solution to the for-loop-closure solution by using with to mimic the let binding, here's a copy of my previous answer:

An alternative to the standard closure solution using functions inside of a for loop:

<a  href="#">blah</a><br>
<a  href="#">blah</a><br>
<a  href="#">foo</a><br>
<script>
    (function() {
    var anchors = document.getElementsByTagName('a');
        for ( var i = anchors.length; i--; ) {
            var link = anchors[i];
            with ({ number: i }) {
                link.onclick = function() {
                    alert(number);
                };
            }
        }
    })();
</script>

Credit to nlogax for providing a solution which I pretty much ripped off: Javascript infamous Loop issue?

Here's the standard solution:

<script>
    (function() {
    var anchors = document.getElementsByTagName('a');
    for ( var i = anchors.length; i--; ) {
        var link = anchors[i];
        (function(i) {
            link.onclick = function() {
                alert(i)
            }
        })(i);
    }
    })();
</script>
Community
  • 1
  • 1
meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
  • 2
    Please make sure you state what part is "ambiguous", as the JavaScript interpreter and/or compiler is never confused about what to use for the identifier. It's future changes and/or what a programmer might interpret an identifier as that is the problem. – Lasse V. Karlsen Dec 18 '09 at 23:16
  • **With modern `const` scoping rules these days you do not need neither of the two**. Just say `for (var i=anchors.length; i--;) { const ii = i; .. alert(ii) ..`. Or even better: `for (let i=..) .. alert(i) ..` because `let` introduces it's own looped scope. Note that in modern Browsers simple examples like yours can be shortened even further: `document.getElementsByTagName('a').forEach((link,i) => link.onclick = () => alert(i))` But this is an entirely different story. – Tino Jul 05 '21 at 21:56
  • @Tino `let` creates a new scope; this is nice. But `let` does not limit the scope; this is not so nice. Lisp did it right, but JavaScript forgot that this could be done right. The nice thing about `with` is, it limits the scope. – ceving Feb 03 '23 at 13:25
  • @ceving Instead of `with ({number:i}) { ..` you can as well write `{ let number=i; ..`. AFAICS this gives the same limited scope (but `let` probably does a better runtime optimization). Please correct me if I did not understand your argument correctly. I will recognize it, but do not want to continue to discuss this in comments ;) PS: Of course: `with ({i}) { ..` cannot be expressed the same with `let`, as `{ let i=i; ..` makes no sense. – Tino Feb 21 '23 at 19:55