0

I am storing css values in an object for use in two different scenarios:

styles = {
  on: { left:10, top:20 },
  off: { left:0, top:30 }
};

The first way I use this is for a simple mouseover effect:

$nav.hover(
  function() {
    $(this).css(styles.on);
  },
  function() {
    $(this).css(styles.off);
  }
);

However, for my other use I am doing an animation and I need extra (non-css) properties like ease and onComplete. Ideally I would like to be able to duplicate the styles object and append my new properties to it like this:

var anim = styles;
anim.ease = Power3.easeInOut;
anim.onComplete = function() {/*stuff*/};

This will work fine for the second use but unfortunately due to storing a reference-by-value this also adds the new properties to the original styles variable as well, which in turn will cause the .css() method to try and assign ease etc as a css value.

How can I quickly clone the source object to add in the new properties without affecting the original?

I am aware of the arguments surrounding whether Javascript can pass by reference (Is there thing like pass by value pass by reference in JavaScript?, Is JavaScript a pass-by-reference or pass-by-value language?) but I don't want to get into a discussion on that...

Community
  • 1
  • 1
͢bts
  • 695
  • 8
  • 32

2 Answers2

1

In this case, a simple object literal, the quick and dirty way would be this:

var anim = JSON.parse(JSON.stringify(styles));

If the styles object will always be as straightforward as this, then you should be OK. Of course, if you're going to mess around with functions (methods), or multi-level, circular references in there, you might need to put a bit more effort into things.

If the styles is unpredictable, but you want to be able to access it from its clone, you could do something like this:

var anim = {on: {}, off: {}};
for (var prop in anim)
{//only loop through anim's properties, as we don't know how many "styles" might have
    if (anim.hasOwnProperty(prop))
    {
        anim[prop].left = styles[prop].left || 'default value';
        anim[prop].top = styles[prop].top || 'default value';
    }
}
anim.original = styles;//reference original object...

In theory, you could create a constructor that uses the original object as a prototype, but that would be somewhat overkill IMHO

Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
1

Do it the other way round (copy from styles to the new object with custom properties) and use $.extend:

$(this).animate($.extend({
   ease: Power3.easeInOut,
   onComplete: function() {/*stuff*/}
}, styles.off));

If you want to override some of them, you also can clone with $.extend by copying properties into a new object:

$(this).animate($.extend({}, styles.off,
   left: 5,
   ease: Power3.easeInOut,
   onComplete: function() {/*stuff*/}
}));
Bergi
  • 630,263
  • 148
  • 957
  • 1,375