Copying objects

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Thomas Mlynarczyk

    Copying objects

    Hi!

    If A is an object, then "B = A;" will just assign a reference. Isn't there a
    simple way to create an actual copy of A and assign that to B?

    Greetings,
    Thomas



  • Lasse Reichstein Nielsen

    #2
    Re: Copying objects

    "Thomas Mlynarczyk" <blue_elephant5 5@hotmail.com> writes:
    [color=blue]
    > If A is an object, then "B = A;" will just assign a reference. Isn't there a
    > simple way to create an actual copy of A and assign that to B?[/color]

    No, not in general.

    There are several ways to do something that resembles it, though, and
    depending on the objects' nature and how you intend to use the copy,
    you can pick the one that suits you best.

    If it is a plain object, you can find all the properties you have added
    using enumeration, and assign them to another object:

    function copyByEnum(obje ct) {
    var copyObject = new Object();
    for(var property in object) {
    copyObject[property] = object[property];
    }
    return copyObject;
    }

    This will not work if the object is not a plain object, but, e.g., a
    function or array. It will only copy enumerable properties. On an
    Object (something created by the user using only "new Object()" and
    inheritance), the only non-enumerable properties are the ones in
    Object.prototyp e. The new copy will also have these because it is
    created with "new Object()".

    If you want to clone an Array, you can first try to detect that it
    is an Array, and then use "copy = new Array(object.le ngth)" instead
    of "copy = new Object()". Detection isn't that easy, and it won't
    help you for functions.

    If you don't want to copy all the properties manually, you can use
    prototype-based inheritance. In a prototype based language like
    Javascript, inheritance happens directly between objects, and not
    through classes as in, e.g., Java. The object you inherit from
    is called the "prototype" , and when you look up properties,
    the ones not found in the new object itself are then searched for
    in its prototype. Assignments will write to the new object directly.

    function copyByInheritan ce(object) {
    function dummyConstructo r(){};
    dummyConstructo r.prototype = object;
    return new dummyConstructo r();
    }

    Again, it won't work for host objects like Arrays and Functions.


    These copy methods have been shallow copies. If one of the properties
    of the object is itself an object, only its reference is copied. If
    you want a deep copy, you will need to look at each property and
    determine whether it is an object that should be deep-copied again.

    All in all, you need a good reason before you start doing any of
    this :)
    /L
    --
    Lasse Reichstein Nielsen - lrn@hotpop.com
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleD OM.html>
    'Faith without judgement merely degrades the spirit divine.'

    Comment

    • Wendy S

      #3
      Re: Copying objects

      "Thomas Mlynarczyk" <blue_elephant5 5@hotmail.com> wrote:[color=blue]
      > If A is an object, then "B = A;" will just assign a reference. Isn't there[/color]
      a[color=blue]
      > simple way to create an actual copy of A and assign that to B?[/color]

      b = a.clone();
      (lowercase letters denote an instance of a class.)

      You have to implement the method for each class you write, if you want it to
      be cloneable. It's not always simple-- if your object contains references
      to other objects, and those contain references to... You have to decide how
      deep of a copy to make.

      --
      Wendy Smoak


      Comment

      • Lasse Reichstein Nielsen

        #4
        Re: Copying objects

        "Wendy S" <wendywds@hotma il.com> writes:
        [color=blue]
        > b = a.clone();
        > (lowercase letters denote an instance of a class.)[/color]

        I''d say they denote objects. There Are No Classes In Javascript(TM)
        (or, if we define something to be called "classes", it will not match,
        e.g., Java's notion of a class very well).
        [color=blue]
        > You have to implement the method for each class you write, if you want it to
        > be cloneable. It's not always simple--[/color]

        Or even possible. In IE (or pretty much anything except Gecko based browsers),
        you can't add to the prototype of DOM nodes.

        (You should also be careful not to clone the clone functions
        unecessarily :)

        /L
        --
        Lasse Reichstein Nielsen - lrn@hotpop.com
        DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleD OM.html>
        'Faith without judgement merely degrades the spirit divine.'

        Comment

        • Thomas Mlynarczyk

          #5
          Re: Copying objects

          Also sprach Lasse Reichstein Nielsen:
          [color=blue]
          > If it is a plain object, you can find all the properties you have
          > added using enumeration, and assign them to another object:
          >
          > function copyByEnum(obje ct) {
          > var copyObject = new Object();
          > for(var property in object) {
          > copyObject[property] = object[property];
          > }
          > return copyObject;
          > }
          >
          > This will not work if the object is not a plain object, but, e.g., a
          > function or array. It will only copy enumerable properties.[/color]

          Thanks for your reply. Meanwhile I have come up with the following:

          function copy(s) {
          for(p in s)
          this[p] = (typeof(s[p]) == 'object')? new copy(s[p]) : s[p];
          }

          a = new copy(b);

          It seems to work as intended. But I haven't yet considered the issue of
          arrays or functions. But shouldn't the above work as well with arrays? Are
          arrays assigned by reference too, like objects? If so, then I should change
          my typeof test to (typeof(s[p]) == 'object' || typeof(s[p]) == 'array').
          Would it work for functions too as expected?

          Greetings,
          Thomas


          Comment

          • Wendy S

            #6
            Re: Copying objects

            "Lasse Reichstein Nielsen" <lrn@hotpop.com > wrote in message
            news:smha38ne.f sf@hotpop.com.. .[color=blue]
            > I''d say they denote objects. There Are No Classes In Javascript(TM)
            > (or, if we define something to be called "classes", it will not match,
            > e.g., Java's notion of a class very well).[/color]

            My apologies! I didn't notice which group the question was posted in and
            assumed I was in comp.lang.java.

            --
            Wendy in Chandler, AZ



            Comment

            • Lasse Reichstein Nielsen

              #7
              Re: Copying objects

              "Thomas Mlynarczyk" <blue_elephant5 5@hotmail.com> writes:
              [color=blue]
              > But shouldn't the above work as well with arrays?[/color]

              It won't. The copy will be an instance of Object, not Array, so it
              won't be an array - just an object with property names that look like
              numbers.
              [color=blue]
              > Are arrays assigned by reference too, like objects?[/color]

              Arrays are objects. They are host objects, so they can act differently
              from user defined objects. You can't inherit "arrayness" . You must be
              created as an array (either using the constructor "new Array(2,3)" or
              a literal "[2,3]").
              [color=blue]
              > If so, then I should change my typeof test to (typeof(s[p]) ==
              > 'object' || typeof(s[p]) == 'array'). Would it work for functions
              > too as expected?[/color]

              The problem is that "typeof [1,2]" is "object". You have to detect
              arrays differently, and there is no absolutely certain way to do
              that. You can try testing with
              perhapsArray.co nstructor == Array
              perhapsArray instanceOf Array
              Array.prototype .isPrototypeOf( perhapsArray)
              but they can all be fooled.

              /L
              --
              Lasse Reichstein Nielsen - lrn@hotpop.com
              DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleD OM.html>
              'Faith without judgement merely degrades the spirit divine.'

              Comment

              • Thomas Mlynarczyk

                #8
                Re: Copying objects

                Also sprach Lasse Reichstein Nielsen:
                [color=blue][color=green]
                >> But shouldn't the above work as well with arrays?[/color]
                >
                > It won't. The copy will be an instance of Object, not Array, so it
                > won't be an array - just an object with property names that look like
                > numbers.[/color]

                Ah, I see. So, for practical purposes, my code would copy arrays too, but
                not into arrays but objects. The implications would be that I could no
                longer use any array specific methods (like join) or properties (like
                length) on the result. In addition, my code will convert any properties
                which are arrays into objects as well.
                [color=blue]
                > perhapsArray.co nstructor == Array
                > perhapsArray instanceOf Array
                > Array.prototype .isPrototypeOf( perhapsArray)
                > but they can all be fooled.[/color]

                How could they be fooled? If the array has non-numeric indices? But then it
                would be treated as an object anyway, wouldn't it?


                Comment

                • Lasse Reichstein Nielsen

                  #9
                  Re: Copying objects

                  "Thomas Mlynarczyk" <blue_elephant5 5@hotmail.com> writes:
                  [color=blue]
                  > Also sprach Lasse Reichstein Nielsen:[/color]
                  [color=blue][color=green]
                  >> perhapsArray.co nstructor == Array
                  >> perhapsArray instanceOf Array
                  >> Array.prototype .isPrototypeOf( perhapsArray)
                  >> but they can all be fooled.[/color]
                  >
                  > How could they be fooled? If the array has non-numeric indices? But then it
                  > would be treated as an object anyway, wouldn't it?[/color]

                  ---
                  function dummyConstructo r(){};
                  dummyConstructo r.prototype = new Array();
                  var nonArray = new dummyConstructo r();

                  alert(nonArray. constructor == Array);
                  alert(nonArray instanceof Array);
                  alert(Array.pro totype.isProtot ypeOf(nonArray) );

                  nonArray[100]=100;
                  alert(nonArray. length); // not an array after all.
                  ---

                  You can try testing for array-like behavior:
                  ---
                  function probablyArray(o bj) {
                  if (! obj.hasOwnPrope rty("length")) {return false;}
                  var n = obj.length;
                  if (obj.hasOwnProp erty(n)) {return false;}
                  obj[n]=true;
                  if (obj.length != n+1) {return false;}
                  obj.length = n;
                  if (obj.hasOwnProp erty(n)) {return false;}
                  return true;
                  }
                  ---
                  However, in some browsers, you might be able to make things act like
                  an array against any test, and still not be an array.

                  /L
                  --
                  Lasse Reichstein Nielsen - lrn@hotpop.com
                  DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleD OM.html>
                  'Faith without judgement merely degrades the spirit divine.'

                  Comment

                  Working...