views:

151

answers:

5

I still find the with keyword a bit...enigmatic.

Briefly, with behaves like this:

with (obj) {
    // do stuff
}

This adds obj to the head of the scope chain and then executes the with-block. When the block is finished it removes obj from the head of the scope chain.

According to MDC, this allows you to do stuff like

var a, x;
var r = 10;
with(Math) {
    a = PI * r * r;
    x = r * cos(PI / 2);
}

So I can reference properties of Math -- like PI -- directly, without saying Math.PI. Which is fine, but kind of useless.

Can anyone provide an example of an interesting usage of with?

+1  A: 

The with statement in JS is like the with statement in say VB.net. It is simply a way to avoid repetition with properties / methods of an object.

For instance, assume a label control is being modified based on an event / action. That label control has properties such as FontColor, CSSClass, Visibility etc.

Instead of the programmer writing:

myLabel.FontColor=Color.Blue
myLabel.CSSClass="SomeCSSClass"
myLabel.Visiblity=True
myLabel.Text = "Hello World"

We can shorten that to:

With myLabel
  .Text = "Hello World"
  .FontColor = Color.Blue
  .CssClass="SomeCSSClass"
  .Visibility=True
End With
JonH
But the JavaScript statement has some serious disadvantages, unlike the VB statement.
Konrad Rudolph
@Konrad, please elaborate.
ntownsend
+4  A: 

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: http://stackoverflow.com/questions/1451009/javascript-infamous-loop-problem

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>
meder
Can you please please provide the standard closure solution version for comparison?
ntownsend
Oh, also...very neat!
ntownsend
done - yeah it is.
meder
+3  A: 

It should be said here that the with statement in JavaScript is widely deprecated.

See Douglas Crockford's With Statement Considered Harmful.

I can't say it any better than he did (seriously, follow the link), but in short if you do this:

with (mySuperLongObjectReferenceThatIHateTyping) {
  propertyAlpha = 'a';
  propertyBeta = 2;
  propertyGamma = false;
}

You can't know by looking at that code if you're assigning values to properties of the mySuperLongObjectReferenceThatIHateTyping object or of the global object (window).

Crockford recommends this:

var o = mySuperLongObjectReferenceThatIHateTyping;
o.propertyAlpha = 'a';
o.propertyBeta = 2;
o.propertyGamma = false;

Which is unambiguous. Or you could even use a function so you have scope and don't create another global variable:

(function(o) {
  o.propertyAlpha = 'a';
  o.propertyBeta = 2;
  o.propertyGamma = false;
})(mySuperLongObjectReferenceThatIHateTyping);
Neall
The money quote: "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."
artlung
+2  A: 

I regularly use it to add multiple CSS properties to a style object, eg

with(document.body.style) {
    color = 'green';
    background = 'red';
}

Also, I used it at least once to assign the properties of an object to local variables without having to store a reference to the object itself.

It's also an alternative to closures when you want to take a 'snapshot' of the value of a variable:

var foo = [];
for(var i = 10; i--;)
    with({ i : i }) foo[i] = function() { document.writeln(i); };

// prints 0..9
for(var i = 0; i < foo.length; ++i)
    foo[i]();

Keep in mind that with can seriously impact performance as the prototype chain of the object you added to the lexical environment has to be checked first when resolving any variable name.

Christoph
+3  A: 

John Resig's javascript microtemplating shows some interesting use for with.

fforw