with Statement Considered Harmful
April 11, 2006 at 7:52 am by Douglas Crockford | In Development |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.
The with statement adds the members of an object to the current scope. Only if there is a bing in ooo.eee.oo.ah_ah.ting.tang.walla.walla will ooo.eee.oo.ah_ah.ting.tang.walla.walla.bing be accessed.
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.
Fortunately, JavaScript also provides a better alternative. We can simply define a var.
var o = ooo.eee.oo.ah_ah.ting.tang.walla.walla; o.bing = true; o.bang = true;
Now there is no ambiguity. We can have confidence that it is ooo.eee.oo.ah_ah.ting.tang.walla.walla.bing and ooo.eee.oo.ah_ah.ting.tang.walla.walla.bang that are being set, and not some hapless variables.
Share and extend: Bookmark with Yahoo! My Web | Bookmark with del.icio.us | digg it! | reddit!
30 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a comment

Copyright © 2007 Yahoo! Inc. All rights reserved. Privacy Policy - Terms of Service
Powered by WordPress on Yahoo! Web Hosting.
Thanks for publishing this useful piece of advice, as it should be known by all JS developers.
Maybe you’ll consider a similar analysis and discussion of the proper uses of the
eval()function. [eval()considerations].Comment by Brad Fults — April 11, 2006 #
I would really love syntax like
with (ooo.eee.oo.ah_ah.ting.tang.walla.walla as o) {
o.bing = true;
bang = true;
}
so you know
ooo.eee.oo.ah_ah.ting.tang.walla.walla.bingand the global variable
bangare set totrue.Just like for example the
foreachconstruct in PHP.$numbers = array(1, 1, 2, 3, 5, 8, 13);
foreach ($numbers as $number)
print $number.' ';
Comment by Frans — April 11, 2006 #
[…] On the Yahoo! user interface blog I just saw their post “with Statement Considered Harmful“. Good advice. […]
Pingback by BarelyBlogging » Blog Archive » Three more things you should not do in JavaScript — April 11, 2006 #
This has to be one of the most entertaining code examples ever. Thanks for sharing it in such an understandable / pallettable way.
Comment by Nathan Smith — April 11, 2006 #
I’m pretty sure the “var” solution is faster too - “with” expands the overall namespace and with JS being dynamic, the walla.walla object will have to be checked upon each variable reference to see if it has a “bang” or a “bing”, ne?
Comment by Michael Mahemoff — April 11, 2006 #
Frans,
Your suggested syntax is not really much different than the “better alternative” suggested by Doug. Personally, I’ve forgotten that “with” even exists and just use this technique.
And I agree, this was a fun code example…
Jeff
Comment by Jeff Schiller — April 12, 2006 #
how about:
function (o) {
o.bing = true;
bang = true;
}(ooo.eee.oo.ah_ah.ting.tang.walla.walla);
Comment by Ron — April 12, 2006 #
[JavaScript] “With” Statement Considered Harmful…
[via qwghlm.co.uk] Over at Yahoo’s User Interface Blog, JavaScript guru Douglas Crockford shows that using JavaScript’s with statement, a bit of syntactic sugar meant to save time and typing, isn’t such a good idea. He points out that in the code
…
Trackback by Tucows Farm: The Tucows Developers' Hangout — April 13, 2006 #
Too bad that Javascript doesn’t use some prefix such as “@” to specify member variables in a
withstatement. eg.with (ooo.eee.oo.ah_ah.ting.tang.walla.walla) {@bing = true;
@bang = true;
}
Something along those lines would make the statement pretty useful still.
Comment by Josh Peters — April 15, 2006 #
Using sensible variable names would probably help a lot more.
Something along the lines of:
with(My.Utils) {
addEvent(…);
var z = append(x, y);
}
is pretty acceptable in my opinion and better than most languages import/using statements because it’s scoped.
Comment by Daniel — April 18, 2006 #
Something along the lines of:
with(My.Utils) {
addEvent(…);
var z = append(x, y);
}
Has 16 possible interpretations. It might mean
var w = My.Utils;
w.addEvent(…);
var z = append(w.x, w.y);
or it could mean
var w = My.Utils;
w.addEvent(…);
var z = w.append(x, y);
or one of 14 others. I can’t read something along these lines and have confidence that I know what it is doing. How can I have confidence that it is correct?
Comment by Douglas Crockford — April 20, 2006 #
Because you’ve used sensible variable names….
If you’ve got a variable called ‘My.Utils.x’ you’ve got bigger problems than the ‘with’ statment.
Which just leaves the possibility that addEvent and append might be in either My.Utils or your current namespace. But why does that matter? Are you in the habbit of creating multiple addEvent functions with contradictory semantics? If so, I hope you’re not putting them in the global scope.
If you think about it, the code I posted has much more than 16 variations. And will if you use ‘with’ or not.
Comment by Daniel — April 21, 2006 #
Consider also this note found at Core Javascript Reference 1.5 by Netscape:
“Note that using a ‘with’ statement will significantly slow down your code. Do not use it when performance is critical.”
I know things have changed and Firefox now includes a new version of JS and maybe IE doesn’t have this problem at all. But I tend to keep it in mind.
Comment by Daniel Fernandez — April 26, 2006 #
[…] Generally a shallow tree is better than a deep tree. One could imagine that YAHOO.util.Dom.get could have been factored more compactly perhaps as YAHOO.get . And perhaps someday it will, but for now YAHOO.util.Dom.get is not measurably slower, and it is helping Yahoo to manage its evolving codebase. (And if you don’t like the length, you only have to type it once. See with Statement Considered Harmful .) […]
Pingback by Global Domination » Yahoo! User Interface Blog — June 1, 2006 #
Ron - Although your method is pretty, I don’t think it is very efficient. To execute your code, the javascript interpreter has to push something onto the call stack, where as setting a local variable works within an already existing stack.
Comment by Taylor — June 30, 2006 #
I knew that headline was familiar
Comment by rymo — August 13, 2006 #
Couple comments:
1. Scope chaining is not something that is only introduced by the “with” statement. Closures do the same exact thing. Any time a function is declared a new scope variable is created and it is nested into or chained to the existing scope. This is basically the same thing that the with statement is doing. Confusion created by these nested scopes can certainly occur with nested closures. This is a core aspect of JavaScript, and I don’t believe it really a great reason to drop “with” usage altogether. The main reason that with statement can create more confusion is that the properties of the object that we are going to do the “with” can and often are set elsewhere, whereas the properties of the current scope are always visible in the immediate code. However, it is certainly possible that code may be structured in such a way that the properties of the “with” object are apparent in the code.
2. Scope chaining used properly can acheive performance enhancement as well degradation. Whenever the JS machine encounters a symbol it must go through the scope chain to do a lookup. If you are referencing a global variable (or any variable not in the top scope, that is the target of the “with” statement), a deeper scope chain will take more time to do a lookup, and this is where performance degradation can be caused by the with statement. However if we consider Douglas’s example, when JS machine encounters o.bing, it must first do a lookup in the current scope for “o” and then it must do a lookup in the o object for “bing”, so it must do two lookups. However, if the with statement is used, there only needs to be one lookup, that is against the current top scope object. I believe that adding another scope on to the scope stack is not a very expensive operation. With these considerations, I believe that code that requires performance tuning (there are situations where code is used heavily enough that performance is more important than readability) may benefit from the “with” statement. Has anyone done any performance tests on the “with” statement (I am curious if my assertions are correct).
Comment by Kris Zyp — September 26, 2006 #
i = new JS_user ;D , so just a wild thought…
What about:
with (ooo.eee.oo.ah_ah.ting.tang.walla) {
walla.bing = true;
}
or…
with (o = ooo.eee.oo.ah_ah.ting.tang.walla.walla) {
o.bing = true;
}
Comment by ec — October 31, 2006 #
Why do you want to be posting stuff which is wrong?
Comment by Douglas Crockford — October 31, 2006 #
The with statement used with an object literal can be a very handy way to assign static variables with less overhead (and thus better performance) than a closure. Using an object literal and with statement in this manner does not open the door to uncertainties, and is conceptually similar to the “let” statement in Javascript 2.
For example, if I write YAHOO.util.Dom and YAHOO.util.Event 57 times each in some program, then I can save quite a few bytes (and a lot of typing) by doing this:
with ({
Dom:YAHOO.util.Dom,
Event:YAHOO.util.Event
}) {
// my program here…
}
This assigns a reference to “YAHOO.util.Dom” to the “Dom” variable, without polluting the global scope.
Comment by Isaac Z. Schlueter — November 12, 2006 #
[…] Normally, the with statement is a pretty bad idea. However, when used with an object literal, it can be a very handy way to create private variables. This: […]
Pingback by Schlueterica » Lessons in Javascript Optimization — January 12, 2007 #
You don’t need with there, either. It is better to use vars in a function. If you want something trickier just to be tricker, try this:
(function (Dom, Event) {
// my program here…
}) (YAHOO.util.Dom, YAHOO.util.Event);
Comment by Douglas Crockford — January 12, 2007 #
[…] they encourage weak coding patterns. JavaScript has more than its share of attractive nuisances (with, implied globals, new, and semicolon insertion, to name a few). Your programs will be stronger if […]
Pingback by I’d Rather switch Than Fight! » Yahoo! User Interface Blog — May 14, 2007 #
Douglas, explain the advantage of using your suggestion of:
(function (Dom, Event) {
// my program here…
}) (YAHOO.util.Dom, YAHOO.util.Event);
over Isaac’s suggestion of:
with ({
Dom:YAHOO.util.Dom,
Event:YAHOO.util.Event
}) {
// my program here…
}
They appear functionally and semantically equivalent.
Comment by Seth Flowers — May 24, 2007 #
Mr. Crockford, you propose a new snippet in your last comment, which is equivalent to :
(function () {
var o = …
o.foo = …
o.bar = …
})();
Thank you for posting it, I was missing the parens around the function statement when I came up with it, and without them the snippet does not work. (I wonder why, actually ?)
However you call that snippet “tricky”. Did you mean to be disparaging, or was it irony ? Because it seems to me that it is the ideal way of implementing your suggestion from the article without polluting the global namespace with the temporary shortcut variables.
Comment by David Holmes — June 7, 2007 #
Responding to myself, to save anyone else the trouble :
I have come to the realization that the above pattern is indeed very common. One can encounter it in the YUI code for example, and I have seen it called a “Crockford Module pattern”.
So, tricky, but very useful !
Comment by David Holmes — June 21, 2007 #
[…] бы всё хорошо и удобно. Но вот мне на глаза попалась статья на YUI-блоге, которую и попробую […]
Pingback by .wpal » Blog Archives » зло with — July 3, 2007 #
[…] C++, porém o estilo Pascal não é recomendado, por causa da natureza dinâmica da linguagem (with-statement-considered-harmful). Como propriedades podem ser adicionadas livremente aos objetos e variáveis globais podem ser […]
Pingback by O “with” em linguagens de programação « blog — July 20, 2007 #
[…] with statement is another that is often recommended to avoid in JavaScript. For YUI Compressor, the reason is the same for eval(): just the presence of with in a function […]
Pingback by Helping the YUI Compressor » Yahoo! User Interface Blog — February 11, 2008 #
This also works:
with ({o:ooo.eee.oo.ah_ah.ting.tang.walla.walla})
{
o.bing = true;
o.bang = true;
}
but reads a little nicer and limits the scope of ‘o’.
Comment by Kevin Greer — May 1, 2008 #