Search code examples
javascriptjqueryobjectcloneextend

JavaScript cloning a "class" instance


I have a class that goes like this:

function Element(){
    this.changes = {};
}

Now I have an instance of this "Class" like so, el = new Element(). These instances are stored in an array, like elements.push(el).

This array of elements is now stored in an object, which is then pushed in an array, states.

Now there are cases where I need a copy of one of the elements, so I would need to do something like, var cloned = $.extend(true, {}, states[0]). Here I assumed that we are cloning the first state.

The problem now is that what I get, the state[1].elements[0] is still pointing to the original instance. Thus any changes I am making to the cloned object, are changing the original too.

It's frustrating to be stuck on such a trivial problem...

Here is a fiddle I created to test it out: http://jsfiddle.net/E6wLW/


Solution

  • $.extend is only cloning plain objects. If the object has a constructor then it is not cloned, but just copied.

    From the $.extend source:

    if ( jQuery.isPlainObject(copy) /* ... */) {
      // do the recursive $.extend call and clone the object                
    } else if ( copy !== undefined ) {
      target[ name ] = copy;
      // ^^^^^ just copy
    }
    

    So $.extend() will call isPlainObject(el) which will return false, because el has an constructor and instead of cloning the el is copied. So states[1].elements[0] is the same object as states[0].elements[0] because it was not cloned.

    If we modify your example from:

    function Element(){
      this.changes = {};
    }
    var el = new Element();    // $.isPlainObject(el); <- false
    // ...
    

    into:

    var el = { changes: {} };  // $.isPlainObject(el); <- true
    // ...
    

    It will clone the el properly. See it HERE.