with Statement Considered Harmful

By Douglas CrockfordApril 11th, 2006

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.

64 Comments

  1. Thomas Devries said:
    April 21, 2010 at 7:21 am

    Hello Crockford I love your speeches an views on javascript but I have looked into the ECMAScript standard and I belive that the with statement can be used but has to be used responsably. It can be dangerous but it can also be vary powerfull. one of the best example uses for the with statement can be found in Firebug. the with statement is safe enough that i don’t think it should be removed from ECMAScript

  2. Thomas Devries said:
    May 12, 2010 at 7:09 am

    the best whey to shrink object refrences that i have found is something like this i have been doing this for quite a while

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

    this is realy useful for doing math heavy algorithoms

    (function($,x){
    return $.cos($.asin(x));
    }(Math,0.5));

  3. You could also write that as

    Math.cos(Math.asin(0.5))

    which would be smaller, faster, and more legible.

  4. why not just prevent any variable assignment within the with block. For example with(object){
    someFunction();
    myArray[10]=someProperty;
    } works but you can’t do with(object){
    x=someProperty
    }

  5. This is all very pretty, and nice to know, and should be accepted as norm of regular code. However, DSLs are very useful, are not normal code in most languages (method chaining technique is famous for breaking Law of Demeter), as Martin Fowler says on his introduction to the topic: As you can see methods defined for Method Chaining violate basic rules for API design. A DSL (with stripped commas for a bit less of noise) that is only possible with the ‘with’ statement (or instance_eval in Ruby):

    DSLRunner.run(function() {
    bake(function() {
    addIngredient(‘flour’)
    addIngredient(‘yeast’)
    addIngredient(‘water’)

    print(“Baking bread”)
    });

    bake(function() {
    print(“Baking a cake”)
    });

    Remember:
    Rebels learn the rules better than the rule-makers do. Rebels learn where the holes are, where the rules can be breached. Become an expert at the rules. Then break them with creativity and style.
    -Kristine Kathryn Rusch

  6. By the same reasoning…


    var test='global';

    function doTest(){
    var test='function';
    return test;
    }

    alert(doTest());
    alert(test);

  7. Okay, I think we can all agree that, when talking about the ooo.eee.oo.ah_ah.ting.tang.walla.walla object, it is NEVER a good idea–due to certain nebulous security issues inherent in the JavaScript engine–to set bing AND bang to true at the same time!

  8. “You could also write that as

    Math.cos(Math.asin(0.5))

    which would be smaller, faster, and more legible.”

    Or you could write it as

    with(Math) cos(asin(0.5));

    Which is even smaller, much more legible, and importantly, far more similar to what real mathematical equations look like.

    I also doubt very much that this is in any significant way slower than referencing ‘Math’ multiple times.

    It is probably not worth the trouble to use ‘with’ for a mere 2 function calls, but if you are doing much more, it seems like a great way to make your code more legible. And in the case of ‘with(Math)’ there is absolutely no ambiguity about what object sin/cos/floor/ceil/pow etc. come from.

  9. [...] way only works if you avoid using the javascript function eval() and statement with, both of which are vilified for their blocking of javascript minifying, among other issues.) A real-world example of [...]

  10. (function(){
    with(this){ // ‘this’ is one of scope chains
    bing = true;
    bang = true;
    }
    }).apply(ooo.eee.oo.ah_ah.ting.tang.walla.walla);

    If ‘bing’ is member of walla, then walla.bing will be setted.
    If ‘bing’ is not member of walla, then bing will be global variant.

  11. [...] geek, loves Mac a… To add, this article and also it's comments highlight few points. http://www.yuiblog.com/blog/2006…  Another point to add, I think it also hurts performance because it adds one more level of scope [...]

  12. The point is not that -with- is useless. The point is that it is, unfortunately, dangerous. And that it is, fortunately, unnecessary. Features that are both dangerous and unnecessary should to be used at all.

  13. This might be a solution to the problem if anyone really needs to use with():

    var obj = {a : ‘foo’, b : ‘bar’}, b = ‘brain’;

    // add _ prefix to object elements
    function _(obj)
    {
    for (var prop in obj)
    this['_'+prop] = obj[prop];
    }

    // write obj.a and obj.b
    with (obj)
    {
    document.write(a);
    document.write(b);
    }

    document.write(”);

    // write obj.a and global b
    with (new _(obj))
    {
    document.write(_a);
    document.write(b);
    }

    // original object still remains
    for (var prop in obj)
    document.write(”+prop+’ = ‘+obj[prop]);

  14. [...] von Scripts können in einen Strict Mode versetzt werden, in dem einige defekte JS-Altlasten (z.B. with(){}) nicht mehr verwendet werden können und der an einigen Stellen die Regeln von JavaScript so [...]