views:

151

answers:

3

I'm looking for a built-in method that combines two associative arrays or objects into one. Using webkit in Adobe Air if that makes a difference. But basically I have two objects or associative arrays if you will:

var obj1 = { prop1: "something", prop2 "anotherthing" };
var obj2 = { prop3: "somethingelse" };

and I want to do merge them and create an object that has all the combined keys and values of the above two objects:

var obj3 = obj1.merge( obj2 ); //something similar to array's concat maybe?

alert(obj3.prop1); //alerts "something"
alert(obj3.prop2); //allerts "anotherthing"
alert(obj3.prop3); //alerts "somethingelse"

Any built in function that does this or do I have to manually do it?

+4  A: 

There is no built-in method. Several libraries provide a method to do what you describe.

Writing one yourself is straightforward:

var merge = function(dest, source){
    // This will resolve conflicts by using the source object's properties
    for (prop in source){
        dest[prop] = source[prop];
    }
}

// Use like so
merge(obj1, obj2);

edit: no longer modifying Object.prototype, which is dangerous and generally frowned upon.

Triptych
BEWARE this implementation. If you have a for( x in obj) loop anywhere in your code, the for loop will iterate over the merge function, unless you explicitly test for that in all your loops. This is probably not what you want.
Breton
That sucks, would be pretty slow with pure javascript with big objects. Too bad it doesn't exist. Makes sense to have something like this doesn't it/
apphacker
In addition, it will modify the original object, which may also not be what you want.
Breton
"That sucks, would be pretty slow with pure javascript with big objects. Too bad it doesn't exist. Makes sense to have something like this doesn't it?" Ecmascript 5 has Object.create, which helps you do something like this. Ecmascript 5 is the new javascript standard, which I expect will be very rapidly adopted by browsers.
Breton
+4  A: 

An alternative implementation to Triptych's (which is essentially the same as Prototype's extend method) is:

/** returns object with properties of both object1 and object2. 
  *  if a collision occurs, properties of object1 take priority
  */
function merge(object1,object2) {
    var retObj = {};
    for (prop in object2){
        retObj[prop] = object2[prop];
    }
    for (prop in object1){
        retObj[prop] = object1[prop];
    }
    return retObj;
}

This doesn't modify the prototype of Object and thus doesn't have it's not insignificant drawbacks.

Jonathan Fingland
+5  A: 

Like tryptych said, except that his example code (was dangerous and wrong, until he edited it). something a little more like the following would be better.

mylib = mylib || {};
//take objects a and b, and return a new merged object o;
mylib.merge = function(a, b) {

  var i, o = {};
  for(i in a) {
      if(a.hasOwnProperty(i)){
          o[i]=a[i];
      }
  }
  for(i in b) {
      if(b.hasOwnProperty(i)){
          o[i]=b[i];
      }
  }

  return o;

}
//take objects a and b, and modify object a to have b's properties
mylib.augment = function(a, b) {
  var i;
  for(i in b) {
      if(b.hasOwnProperty(i)){
          a[i]=b[i];
      }
  }
  return a;
}

edit re: ferocious. Deep copy is a different, and orthogonal function to this, but just for you, here's my personal deep copy function

   function clone(o) {
    var t,i;
    if (o === undefined) {
        return undefined;
    }
    if (o === null) {
        return null;
    }
    if (o instanceof Function) {
        return o;
    }
    if (! (o instanceof Object)) {
        return o;
    } else {
        t = {};
        for (i in o) {
            /* jslint complains about this, it's correct in this case. I think. */
            t[i] = clone(o[i]);
        }
        return t;
    }
   }
Breton
I like this one, but could you mod it to do a deep copy (copy the objects within it)?
larson4
done, (sorta), mylib.merge(clone(a),clone(b)) for essentially the effect you're after.
Breton

related questions