Fork Me
webcloud / log / JavaScript and the with statement

When passing an object to with you temporarily gain shortcut access to its variable scope. It can be useful at times, but it may cause you more trouble than good. Imagine the following scenario:

var el = document.getElementById('el');
el.style.backgroundColor = '#000';
el.style.color = '#fff';
el.style.width = '200px';
el.style.padding = '20px';

The above is perfectly legal code, but lets rewrite it a bit.

with(document.getElementById('el').style) {
    backgroundColor = '#000';
    color = '#fff';
    width = '200px';
    padding = '20px';
}

Personally I think it's a pretty clean approach. Although the workings are completely different, it somewhat resembles the way jQuery is used when styling elements:

$("#el").css({
    backgroundColor : '#000',
    color : '#fff',
    width : '200px',
    padding : '20px',
});

One thing to note is that the "this" context does not change, and you can still access objects in that context.

var foo = "bar",
    obj = { 
        hello: "world",
        outside : "warm"
    },
    outside = "cold";
with(obj) {
    hello = "javascript";
    console.log(outside); // warm
    console.log(this.outside); // cold
    console.log(foo); // bar
}

You can see that if a property in the scoped object does not exist (foo), it'll access the outside property, this can be somewhat confusing.

The controversy

There are quite a few voices that advice against the usage of with because of it's performance implications and somewhat unpredictable behavior that code may result in. Let's take a look at some of these problems.

“It was well intentioned, but the language would be better if it didn't have it.” — Douglas Crockford

Implicit globals

Using with you cannot add new properties to an object. If you try to do this, it will instead become a global variable, which is very much undesired.

Consider the following:

with(document.getElementById('el').style) {
    colors = '#fff'; //oops we mispelled this property
}

Because the property colors, does not exist we now have a new impicit global variable. Always make sure that properties exist before trying to modify them.

Performance

Optimizing with for speed is difficult and it's best avoided when used in code that go through many iterations. Take this very unscientific basic test as an example:

var obj = { hello: "world" }, 
    value;
function without_with () {
    for ( var i = 0; i < 9999; i++ ) {
        value = obj.hello;
    }
}
function with_with() {
    with(obj) {
        for ( var i = 0; i < 9999; i++ ) {
            value = hello;
        }
    }
}

Profiling theses functions in Firebug+Firefox 3.6, we get some interesting results:

Function Calls Percent Own Time Time Avg Min Max
with_with 10 91.08% 96.549ms 96.549ms 9.655ms 9.487ms 9.919ms
without_with 10 8.92% 9.453ms 9.453ms 0.945ms 0.931ms 0.959ms

As we can see, over a large set of iterations, there is a little performance hit, so using the with statement in heavy duty operations is best avoided.

I've set up a test case on jsperf so you can test performance by yourself.

Conclusion

In my opinion, as long as you are aware of the caveats of with and how it works, it's OK to use. But mostly, I think that the trade-offs are bigger than the benefits.

References and further reading

Books

On the web