Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery extend overwrites wrong values

I'm using jQuery extend in a plugin to overwrite the default parameters. However, I have a problem.

Here's my default settings array:

slider.settings = {
            background: {
                animation : {
                    direction : 'horizontal',
                    increment : 15 //can be any number
                }
            }
        }

Now, I want to overwrite the direction parameter. Here's the array that I will merge with using extend:

    settingsToOverwrite = {
        background:{
            animation:{
                direction:'vertical'
            }
        }
    }

Now, I merge the two:

slider.settings = $.extend(slider.settings, options)

I can see that the direction value has been updated. However, increment is no longer there. I know that to avoid this problem I could only set parameters at the first level but I see more code clarity in doing my way. Is there a way to do so ? If not, I will change everything to be only one level deep.

like image 351
Etienne Noël Avatar asked Jul 28 '13 23:07

Etienne Noël


2 Answers

By default, jQuery.extend() only compares the immediate properties, performing a "shallow merge." Since both objects have background, it simply takes the entire background from the 2nd object.

But, pass a true as the 1st argument, and jQuery.extend() will perform a "deep merge."

slider.settings = $.extend(true, slider.settings, options);

Also, since the 1st Object is the target and will be both modified and return'd, you can update slider.settings with just:

$.extend(true, slider.settings, options);

And, if you'd rather have a new Object from the merge, you'll have to create it yourself:

slider.settings = $.extend(true, {}, slider.settings, options);
like image 79
Jonathan Lonowski Avatar answered Nov 14 '22 11:11

Jonathan Lonowski


You are right, this is obviously happening because jQuery's extend is "shallow extending" the object.. thus replacing the entire "animation" property.

To fix this, use your brandy dandy deepExtend:

Object.deepExtend = function(destination, source) {
  for (var property in source) { // loop through the objects properties
    if (typeof source[property] === "object") { // if this is an object
      destination[property] = destination[property] || {};
      Object.deepExtend(destination[property], source[property]); // recursively deep extend
    } else {
      destination[property] = source[property]; // otherwise just copy
    }
  }
  return destination;
};

You can use it as follows:

slider.settings = Object.deepExtend(slider.settings, options);
like image 2
Yotam Omer Avatar answered Nov 14 '22 11:11

Yotam Omer