Question

The following doesn't work (although it gives no explicit error), but why not?

And... Is there really no way around it, strictly using the with statement? Forget using for / foreach.

with (object1, object2) {
  attribute = value;
  method();
}

edit: Sorry to make 2 questions in 1. I'll try to make it clearer:

  1. Why the code above gives no syntax error, doesn't work but is accepted by with?

  2. If it's possible, how could we change multiple objects with same attribute using with?

Hopefully the following example will be more clear on what I wanted to accomplish:

var object1 = { attribute: 3 };
var object2 = { attribute: 2, method: function() { alert('blah'); } };
var object3 = { method: function() {alert('bleh'); } };

var value = 4;

with (object1) 
with (object2) 
with (object3) 
{
  attribute = value;
  method();
}

alert(object1.attribute + object2.attribute);

// resulting alerts should be, in order: blah, bleh, 8
Was it helpful?

Solution

Introducing multi-object scope with with

This is what I originally thought you were after, since you hadn't specified what your expected results were. Just stack the with statements:

var object1 = { attribute: 3 };
var object2 = { method: function() { alert('blah'); } };

var value = 4;

with (object1) 
with (object2) 
{
  attribute = value;
  method();
}

alert(object1.attribute);

Naturally, the object introduced by the inner-most with will override identically-named properties in any outer scope, including those of the outer with statements.

Standard disclaimers apply regarding performance hits and potential for errors caused by the use of with. Note that your example shows property access prefixed by . within the block, but this is incorrect - with modifies scope, temporarily putting an object at the front of the resolution chain, so no prefix is necessary (or allowed).


Targeting multiple objects

Regarding your edit: the comma operator lets you write something that appears to pass multiple expressions to with, but really only passes one of them. You're not going to be able to accomplish what you want without some sort of multicast delegate implementation (one that involves looping); JavaScript/ECMAScript don't have any built-in means of modifying multiple properties / calling multiple methods with a single assignment / call.

Quick 'n' dirty implementation:

function multicast()
{
  this.targets = Array.prototype.slice.call(arguments, 0);
}
multicast.prototype = {
  call: function(methodName)
  {
    var i;
    for (i=0; i<this.targets.length; ++i)
    {
      if ( this.targets[i][methodName] )
        this.targets[i][methodName].apply(this.targets[i],
          Array.prototype.slice.call(arguments, 1));
    }
  },
  set: function(propName, value)
  {
    var i;
    for (i=0; i<this.targets.length; ++i) 
      this.targets[i][propName] = value;
  }
};

Usage:

var object1 = { attribute: 3 };
var object2 = { attribute: 2, method: function() { alert('blah'); } };
var object3 = { method: function() {alert('bleh'); } };

var value = 4;

var delegate = new multicast(object1, object2, object3);
delegate.set('attribute', value);
delegate.call('method');

alert(object1.attribute + object2.attribute);

OTHER TIPS

You can also use a reference to the object if you want to make your code shorter:

var o1 = object1
,   o2 = object2
;
o1.attribute = value;
o2.method();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top