with(obj) { ... } a necessary evil.
For those who haven't seen the statement yet, the with() statement in JavaScript allows an object to be pushed onto the scope chain.
In short the common reason for it to be useful is if you had something like foo.bar.baz.a
and foo.bar.baz.b
then instead of typing that over and over you could use something like with(foo.bar.baz) { a; b; }
.
Unfortunately nearly every example people show is a poor example of how to use it, and then Crockford went and published a classic "Considered Harmful"[2] article describing a single very bad example of how to use with()
, why with()
is bad because of that one poor use, and as a result most people's opinion about with() is that the statement is evil "cause Crockford said so" without even thinking of good uses for the feature.
For a short overview of Crockford's article, he posted the bit of code:
ooo.eee.oo.ah_ah.ting.tang.walla.walla.bing = true
ooo.eee.oo.ah_ah.ting.tang.walla.walla.bang = true
And said it could be replaced with:
with (ooo.eee.oo.ah_ah.ting.tang.walla.walla) {
bing = true
bang = true
}
Crockford then explained that the statement is ambiguous because bing and bang will only be set on the object if the property existed on the object, if it didn't then it would fallthrough and set it on the global object.
What he failed to note however, is if instead of that you used this:
with (ooo.eee.oo.ah_ah.ting.tang.walla) {
walla.bing = true
walla.bang = true
}
The properties would be set properly. Of course there is still the case where the .walla is not set. I'm not going to argue that, what I am going to argue is misuse of a feature does not constitute a feature is bad. Yes, this is a possible use of with()
but is it really the only thing with()
could be used for, and are these cases even valid in practical use of other uses of with()
or are these edge cases like the ones lots of features suffer from but the features themselves are still considered useful?
To continue let's jump into the other use of with()
, importing a namespace. JavaScript users have begun to adopt the convention of isolating all their code into a JavaScript object as a namespace to keep their methods and properties out of the global object and avoid clashing.
For example, let's take json-template and YUI. json-template defines the namespace jsontemplate
which contains Template. And YUI defines YAHOO
, and a number of sub namespaces. In this case we want some of the YAHOO.util stuff, primarily the Dom class.
with (jsontemplate)
with (YAHOO.util) {
var tpl = new Template("...")
var content = tpl.expand()
Dom.get("someNodeId").innerHTML = content
}
I find the use of with()
to import modularized code into the local scope a great use for it. In fact by this case with()
is basically the closest thing to things like python's import or other languages where you can simply import everything from another module into the local area. It might just be me, but I really don't feel like explicitly defining every single class I'm importing using a syntax that makes me type the same name twice.