tags:

views:

40

answers:

5

I'm looking for an elegant way to override values in an associative array.

For example, say I have my base options as:

var base_options = {
    hintText:"something",
    borderStyle:Titanium.UI.INPUT_BORDERSTYLE_ROUNDED,
    width: 200, height: LABEL_HEIGHT-4,
    font: {fontSize:16}, left: 95
}

I want to use this as the base, but be able to override a few items in this base on a case-by-case basis - for example, hintText would be different for each item. What's a clean and elegant way to get a copy of this array with a few parameters modified?

I realize I can change each individual item, as in:

options.hintText = "new thing";

but I suspect there's a more elegant way.

A: 

Something like this?

var changed_options = { 
   hintText: "somethingElse",
   font: {fontSize: 24} 
}

for(var prop in changed_options) 
    base_options[prop] = changed_options[prop];
Weston C
Shouldn't it be `base_options[prop] = changed_options[prop];`?
Zebi
Good catch, Zebi -- edited.
Weston C
A: 
function merge(base, options) { 
   var result = {};
   for (var k in base) if (base.hasOwnProperty(k)) {
      result[k] = options[k] || base[k];
   } // note, it will leave out properties that are in options, but not in base..
   return result;
}

If you happen to be using jQuery, it has a built in extend method on the jQuery object that does this.

CD Sanchez
A: 
var base_options = function() { 
    hintText:arguments[0], 
    borderStyle:arguments[1], 
    width:arguments[2],
    height:arguments[3], 
    font:arguments[4]
    left:arguments[5]
};

var thisObj = new base_option(blah, blah, blah, blah, blah);

That may seem like overkill but then you can add all of the new instances to an array and use a for loop for them when you want/need to change them.

John
This is **very** fragile code. Referencing arguments by index gets you in problems very fast and it's not especially nice to read.
Zebi
If your going to downvote and answer please explain why. This will help me not post wrong answers if it is wrong. Thank you. // Sorry @Zebi, my page was slow on the update.
John
It depends on the coder and thier understanding of the code they are writing. It is no diffirent than writing a for loop using the index to access each property in an array, no?
John
It's different because if you are using for you can not mismatch properties because the order changed. You can not forget to add a property and finally you don't answer the question asked because you don't merge default values with overridden values.
Zebi
A: 

I have implemented this function in a few of my projects:

if (typeof Object.merge !== 'function') {
    Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
        for(var i in o2) { o1[i] = o2[i]; }
        return o1;
    };
} 

So, now I can use it like:

Object.merge(options, {hintText: "new thing", left: 55});

As far as copying objects, there is already a good StackOverflow discussion about that.

palswim
+1  A: 

You could use a base class to encapsulate the behavior Weston propose.

function Options(changed_options) {
     this.hintText = "something";
     this.borderStyle =Titanium.UI.INPUT_BORDERSTYLE_ROUNDED;
     // ...

     if(changed_options)
         for(var prop in changed_options) 
             this[prop] = changed_options[prop];
}

var foo = new Options({ "hintText":"changed"});

Should work.

Zebi
This is a nice solution because there's a smaller chance of accidentally changing the base object by copying an object reference (in the font property, for example) to the new object. If you want to avoid that with the other solutions, you'd have to create copies of the objects.
CD Sanchez