Duplicating objects

Discussion in 'Javascript' started by Christopher Benson-Manica, Dec 6, 2005.

  1. Is there a general mechanism to duplicate, or provide for the
    duplication of, objects? As an example, suppose I need to duplicate
    an array. I can accomplish this with array.slice( 0 ), but that's not
    going to cut in general. I could also add a copy method to the Array
    prototype, like so:

    Array.prototype.copy=function() {
    var newArray=[];
    for( var idx=0; idx < this.length; idx++ ) {
    newArray.push( this[idx] );
    }
    return newArray;
    }

    and I could write similar copy() methods for various objects. But I
    feel certain that I'm not the first programmer who has had a need for
    such functionality. What is the canonical way of doing this?

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Dec 6, 2005
    #1
    1. Advertising

  2. Christopher Benson-Manica

    Evertjan. Guest

    Christopher Benson-Manica wrote on 06 dec 2005 in comp.lang.javascript:

    > Is there a general mechanism to duplicate, or provide for the
    > duplication of, objects? As an example, suppose I need to duplicate
    > an array. I can accomplish this with array.slice( 0 ), but that's not
    > going to cut in general. I could also add a copy method to the Array
    > prototype, like so:
    >
    > Array.prototype.copy=function() {
    > var newArray=[];
    > for( var idx=0; idx < this.length; idx++ ) {
    > newArray.push( this[idx] );
    > }
    > return newArray;
    >}
    >


    Array.prototype.copy=function() {
    return this.concat();
    }

    or simply us an empty .concat() by itself:


    var b = a.concat()


    --
    Evertjan.
    The Netherlands.
    (Replace all crosses with dots in my emailaddress)
     
    Evertjan., Dec 6, 2005
    #2
    1. Advertising

  3. Christopher Benson-Manica

    VK Guest

    Christopher Benson-Manica wrote:
    > Is there a general mechanism to duplicate, or provide for the
    > duplication of, objects? As an example, suppose I need to duplicate
    > an array. I can accomplish this with array.slice( 0 ), but that's not
    > going to cut in general. I could also add a copy method to the Array
    > prototype, like so:
    >
    > Array.prototype.copy=function() {
    > var newArray=[];
    > for( var idx=0; idx < this.length; idx++ ) {
    > newArray.push( this[idx] );
    > }
    > return newArray;
    > }
    >
    > and I could write similar copy() methods for various objects. But I
    > feel certain that I'm not the first programmer who has had a need for
    > such functionality. What is the canonical way of doing this?


    There is not such so feel free to propose one ;-)
    JavaScript object doesn't have clone() method.

    So in case of array your options are:
    1) If array doesn't have other arrays in it (psi-"single-dimention")
    you use:
    var arrayOneCopy = arrayOne.slice(0);

    2) If array does have other arrays in it (psi-"multi-dimention") you
    use your code but just make it *recursive* and check for each single
    element if it's not an array.

    3) Also if you don't mind of JSON then you can

    var arrayOneCopy = JSON.parse(JSON.stringify(arrayOne));
     
    VK, Dec 6, 2005
    #3
  4. <>
    VK <> wrote:

    > There is not such so feel free to propose one ;-)


    Surely someone has already done so? I can't imagine I'm the first
    person who's wanted duplicated objects...

    > JavaScript object doesn't have clone() method.


    Any particular reason for that?

    > 2) If array does have other arrays in it (psi-"multi-dimention") you
    > use your code but just make it *recursive* and check for each single
    > element if it's not an array.


    Well, as long as I'm proposing things...

    Object.prototype.copy=function( deep ) {
    return this; // Use references by default
    }

    Array.prototype.copy=function( deep ) {
    var c=[];
    for( var idx=0; idx < this.length; idx++ ) {
    if( deep ) {
    c.push( this[idx].copy(true) );
    }
    else {
    c.push( this[idx] );
    }
    }
    return c;
    }

    --
    Christopher Benson-Manica
    ataru(at)cyberspace.org
     
    Christopher Benson-Manica, Dec 6, 2005
    #4
  5. Christopher Benson-Manica <> wrote:

    > Array.prototype.copy=function( deep ) {
    > var c=[];
    > for( var idx=0; idx < this.length; idx++ ) {
    > if( deep ) {
    > c.push( this[idx].copy(true) );
    > }
    > else {
    > c.push( this[idx] );
    > }
    > }
    > return c;
    > }


    Let me try again:

    Array.prototype.copy=function( deep ) {
    if( !deep ) {
    return this.concat();
    }
    var c=[];
    for( var idx=0; idx < this.length; idx++ ) {
    c.push( this[idx].copy(true) );
    }
    return c;
    }

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Dec 6, 2005
    #5
  6. Christopher Benson-Manica

    RobG Guest

    Christopher Benson-Manica wrote:
    > Christopher Benson-Manica <> wrote:
    >
    >
    >>Array.prototype.copy=function( deep ) {
    >> var c=[];
    >> for( var idx=0; idx < this.length; idx++ ) {
    >> if( deep ) {
    >> c.push( this[idx].copy(true) );
    >> }
    >> else {
    >> c.push( this[idx] );
    >> }
    >> }
    >> return c;
    >>}

    >
    >
    > Let me try again:
    >
    > Array.prototype.copy=function( deep ) {
    > if( !deep ) {
    > return this.concat();
    > }
    > var c=[];
    > for( var idx=0; idx < this.length; idx++ ) {
    > c.push( this[idx].copy(true) );
    > }
    > return c;
    > }
    >


    That will only work where all the elements of the array are arrays, and
    it fails when it gets to elements that aren't arrays.

    Here's my test:

    var a = [[1,2,3],1,2,3];
    var b = a.copy(true); // 'this[idx].copy is not a function'
    a[0][1] *=5;
    alert(a[0] + '\n' + b[0]);

    Here's a copy method based on something I wrote some time ago to copy
    multi-dimensional arrays:

    Array.prototype.copy=function() {
    var A = this;
    var B = [];
    for (var i=0, j=A.length; i<j; ++i){
    if (typeof A == 'object' && Array == A.constructor ){
    B = arrayCopy(A);
    } else {
    B = A;
    }
    }
    return B;
    }

    It is very much slower than concat(), but for small arrays it may be OK.

    It will also only work on arrays of primitives, it will not work if an
    element is an object other than an array. You could extend it to handle
    other types of objects, but that's pretty much what JSON.parse does, so
    VK's JSON.parse suggestion may be better.

    <URL:http://www.crockford.com/JSON/js.html>

    --
    Rob
     
    RobG, Dec 6, 2005
    #6
  7. Christopher Benson-Manica wrote:
    > Is there a general mechanism to duplicate, or provide
    > for the duplication of, objects?


    No.

    > As an example, suppose I need to duplicate
    > an array. I can accomplish this with array.slice( 0 ),
    > but that's not going to cut in general. ...

    <snip>
    > and I could write similar copy() methods for various
    > objects. But I feel certain that I'm not the first
    > programmer who has had a need for such functionality.


    You are not but the reason for copying an object has a big influence
    upon how you would go about it. For example, prototype-based clones can
    be useful:-

    var protoCloneObject = (function(){
    function constr(){
    ;
    }
    return (function(obj){
    constr.prototype = obj;
    return new constr();
    });
    })();

    - so that you can create an object as:-

    var firstObj = new SomeObject(x, y, z);

    - and then create a new object that has all of the properties and
    methods of the first object with:-

    var clone = protoCloneObject(firstObj);

    - but is still a distinct object instance. With the significant proviso
    that acting upon the copy will modify the copy but acting upon the first
    object will also modify all of its copies until those copies have been
    modified in a way that masks the changes in their prototype.

    So in some circumstances the result is exactly what you need, and in
    others it is extremely dubious.

    > What is the canonical way of doing this?


    There isn't, and there probably should not be one.

    Richard.
     
    Richard Cornford, Dec 6, 2005
    #7
  8. RobG <> wrote:

    > That will only work where all the elements of the array are arrays, and
    > it fails when it gets to elements that aren't arrays.


    Well, in my previous post, I had

    Object.prototype.copy=function() {
    return this;
    }

    which should make it conceptually a no-op except for classes which
    overrride copy.

    > It will also only work on arrays of primitives, it will not work if an
    > element is an object other than an array. You could extend it to handle
    > other types of objects, but that's pretty much what JSON.parse does, so
    > VK's JSON.parse suggestion may be better.


    I will take a look at that in the morning; thanks.

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Dec 7, 2005
    #8
  9. Christopher Benson-Manica

    Guest

    sure!
     
    , Dec 7, 2005
    #9
  10. Christopher Benson-Manica wrote:

    > RobG <> wrote:
    >> That will only work where all the elements of the array are arrays, and
    >> it fails when it gets to elements that aren't arrays.

    >
    > Well, in my previous post, I had
    >
    > Object.prototype.copy=function() {
    > return this;
    > }
    >
    > which should make it conceptually a no-op except for classes which
    > overrride copy.


    Again: there are _no_ classes in the languages usually discussed
    here (ECMAScript implementations in a client-side environment);
    those are OO languages using prototype-based inheritance.

    Your method returns a reference to the calling object; that is not
    copying an object, it is retrieving a reference to that object.
    Given your prototype method above:

    var x = {foo: 'bar'}; // x.foo == 'bar'
    var y = x.copy(); // y.foo == 'bar'
    y.foo = 42; // y.foo == 42
    alert(x.foo); // 42 (not 'bar')

    Graphically, that is:

    1. object1
    2. x --------> object1
    3. x --------> object1 <-------- y

    What you wanted is:

    1. object1
    1. x --------> object1
    2. object2
    3. Copy all properties and property values from object1 to object2.
    4. object2 <-------- y


    PointedEars
     
    Thomas 'PointedEars' Lahn, Dec 8, 2005
    #10
  11. Christopher Benson-Manica

    Jambalaya Guest

    VK wrote:
    > Christopher Benson-Manica wrote:
    > > Is there a general mechanism to duplicate, or provide for the
    > > duplication of, objects?

    >
    > 3) Also if you don't mind of JSON then you can
    > var arrayOneCopy = JSON.parse(JSON.stringify(arrayOne));


    And since security is not a concern as this data already exists in a
    local variable, this would be faster.
    var arrayOneCopy = eval(JSON.stringify(arrayOne));

    Probably one of the only times I would feel comfortable with eval.
     
    Jambalaya, Dec 8, 2005
    #11
  12. Thomas 'PointedEars' Lahn <> wrote:

    > Your method returns a reference to the calling object; that is not
    > copying an object, it is retrieving a reference to that object.


    That's intentional. If an object's prototype doesn't override the
    inherited copy(), it doesn't copy itself. That seems like reasonable
    default behavior to me.

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Dec 8, 2005
    #12
  13. Christopher Benson-Manica wrote:

    > Thomas 'PointedEars' Lahn <> wrote:
    >> Your method returns a reference to the calling object; that is not
    >> copying an object, it is retrieving a reference to that object.

    >
    > That's intentional. If an object's prototype doesn't override the
    > inherited copy(), it doesn't copy itself. That seems like reasonable
    > default behavior to me.


    It does not seem to me, given that Object objects are
    extensible, too, without inheriting from another prototype.

    My example shows that your approach fails badly on those,
    and an approach that fails even with the simplest of objects
    can hardly be considered viable for a general solution.


    PointedEars
     
    Thomas 'PointedEars' Lahn, Dec 8, 2005
    #13
  14. Thomas 'PointedEars' Lahn <> wrote:

    > It does not seem to me, given that Object objects are
    > extensible, too, without inheriting from another prototype.


    I'm not sure I get you here.

    > and an approach that fails even with the simplest of objects
    > can hardly be considered viable for a general solution.


    Yes, I haven't provided a way for any generic object to be copied.
    For my purposes, however, the ability to specify whether objects of
    prototype X are copied by reference or value is good enough for a
    number of purposes, not least of which is solving the minor problem
    that motivated this line of questioning in the first place.

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Dec 8, 2005
    #14
  15. Christopher Benson-Manica wrote:

    > Thomas 'PointedEars' Lahn <> wrote:
    >> It does not seem to me, given that Object objects are
    >> extensible, too, without inheriting from another prototype.

    >
    > I'm not sure I get you here.


    var x = {foo: 'bar'};

    is defining the reference `x' to a newly created Object object,
    that is extended by adding a new property, `foo'. It is the same
    as

    var x = new Object();
    x.foo = 'bar';

    That object is extensible and extended here without the use of another
    prototype (object). And since all non-host objects are extensible ...

    >> and an approach that fails even with the simplest of objects
    >> can hardly be considered viable for a general solution.

    >
    > Yes, I haven't provided a way for any generic object to be copied.
    > For my purposes, however, the ability to specify whether objects of
    > prototype X are copied by reference or value is good enough for a


    "copied by reference or value"? Object references and primitive values
    are the only property values you can copy this way. References _are_
    values in JS.

    > number of purposes, not least of which is solving the minor problem
    > that motivated this line of questioning in the first place.


    Fair enough, but you need to be aware, and I am not sure that you already
    are, that, consequently, copying properties which values are references to
    Object objects (or any user-defined object that does not have a constructor
    with a prototype object that defines anything different for that matter),
    will not result in copying those objects. It will merely result in copying
    the reference to that object, hence modifying the property of such
    properties of original object1 will result in modifying the property of
    such properties of its "copy" object2:

    var object1 = {foo: {bar: 42}};
    var object2 = object1.copy();
    object2.foo.bar = 23;
    alert(object1.foo.bar); // 23, not 42

    1. original object
    2. object1 --------> original object
    3. object1.foo ----> {bar: 42}
    4. Create "copy" of object1.
    5. _Copy_ property _values_ from object1 to object2.
    6. "copy" <-------- object2
    7. object1.foo ----> {bar: 42} <------- object2.foo

    That goes of course for all objects where only shallow copying of property
    values is performed.


    PointedEars
     
    Thomas 'PointedEars' Lahn, Dec 8, 2005
    #15
  16. Thomas 'PointedEars' Lahn <> wrote:

    > "copied by reference or value"? Object references and primitive values
    > are the only property values you can copy this way. References _are_
    > values in JS.


    All right, I'll put it another way - the ability to choose whether the
    reference I get is to the original object or a new object with the
    same properties.

    > Fair enough, but you need to be aware, and I am not sure that you already
    > are, that, consequently, copying properties which values are references to
    > Object objects (or any user-defined object that does not have a constructor
    > with a prototype object that defines anything different for that matter),
    > will not result in copying those objects.


    Yes, I am aware of that fact, and that is actually the precise
    behavior I'm looking for. I do appreciate the heads up all same,
    however.

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Dec 8, 2005
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. AC
    Replies:
    0
    Views:
    570
  2. Don

    Duplicating datasheet screens

    Don, Feb 23, 2005, in forum: ASP .Net
    Replies:
    0
    Views:
    372
  3. Todd Plambeck

    ASP.Net Duplicating DB Entries

    Todd Plambeck, Aug 5, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    513
  4. George Jempty

    log4j duplicating appender entries

    George Jempty, Jan 7, 2005, in forum: Java
    Replies:
    2
    Views:
    2,542
  5. Pete Nudd
    Replies:
    3
    Views:
    358
    Denis Remezov
    Apr 16, 2004
Loading...

Share This Page