locked
How do I clone an object

    Question

  • I have an object that I want to save before I make changes to it.  So I do something like this:

    originalCustomer = myCustomer;

    myCustomer.FirstName = "New Name";

    originalCustomer.Firstname is also changed to "New Name".  I want it to have the original value prior to change but it is just a point to myCustomer.  How do I make a copy (clone) of myCustomer?

    PS: I found this http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object but I wanted to check if there was a more "metro" way...


    www.emadibrahim.com

    Thursday, May 17, 2012 12:24 AM

Answers

  • I guess no one is reading my posting...   This is the best answer so far and it is ONE LINE OF CODE....  You will have to reference jquery though.

    // Shallow copy
    var newObject = jQuery.extend({}, oldObject);

    // Deep copy
    var newObject = jQuery.extend(true, {}, oldObject);


    www.emadibrahim.com

    Monday, May 21, 2012 12:28 PM
  • Minor aside- since this is a Metro style app, you have ES5 support, which means you can use Object.getOwnPropertyNames (http://msdn.microsoft.com/en-us/library/ff688126(v=VS.94).aspx) to get non-enumerable properties if those are important to you.

    There is an interesting IE blog post that goes into how to do things like cloning, with ES5 code examples: http://blogs.msdn.com/b/ie/archive/2010/10/27/ecmascript-5-part-1-reusable-code.aspx

     

    Cheers,

    -Jeff

    Thursday, May 24, 2012 10:36 PM
  • Very nice Jeff!

    So we can re-write the clone to be:

    Object.clone = function (o) {
      var n = Object.create(Object.getPrototypeOf(o));
      var props = Object.getOwnPropertyNames(o);
      var pName;
      for (var p in props) {
        pName = props[p];
        Object.defineProperty(n, pName, Object.getOwnPropertyDescriptor(o, pName));  
      };
      return n;
    };

    and the sample code would be:

     function btnClick(event) {
            txtContent.innerText = "clicked";
            var newcustomer = { firstName: "Jeff", lastName: "Sanders" };
            var copyCustomer = Object.clone(newcustomer);
            copyCustomer.firstName = "Jimmy";
            txtContent.innerText = newcustomer.firstName;
        }

    -Jeff

    Jeff Sanders (MSFT)

    Friday, May 25, 2012 11:57 AM
    Moderator

All replies

  • Hi,

    "originalCustomer" and "myCustomer" use the same memory. So you need to create a new object to allocate a new memory, and your code to be like this:

    var originalCustomer = new Customer();
    originalCustomer = myCustomer;
    myCustomer.FirstName = "New Name";

    With assumption Customer is your object class.
    Hope this can help


    Jannen Siahaan - Indonesia

    Thursday, May 17, 2012 1:17 AM
  • I haven't tried this but I don't think that will work...  calling new Customer() will create a new object but then you overwrite that on your next line - so it adds no value.

    The method mentioned in the stackoverflow link above worked well.


    www.emadibrahim.com

    Friday, May 18, 2012 9:16 PM
  • Hi

    In C# when we make "var originalCustomer = new Customer();" is instantiated class Customer() to be a new object and allocate a new memory location. This is NOT calling new Customer() but define an object with class Customer(). At the "originalCustomer = myCustomer;" give a value to "originalCustomer", here memory location for originalCustomer and myCustomer are in two location and two different object with the same class, this is NOT overide new Customer(). In your code it used only one memory location it is one object with two names. That is why in your code when you change in one of them the other one has the same value.

    In my reply this is not happened, because it use two different memory location and two objects with the same class.

    That is how C# is designed.

    Regards


    Jannen Siahaan - Indonesia


    • Edited by humaNiT Friday, May 18, 2012 11:51 PM
    Friday, May 18, 2012 11:46 PM
  • Hi Emad,

    You are absolutely right. I tested it with this code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication3
    {
        class Program
        {
            static void Main(string[] args)
            {
                Person mike = new Person();
                mike.FirstName = "Michael";
                mike.LastName = "Bolton";
    
                Person bob = new Person();
                bob.FirstName = mike.FirstName;
                bob.LastName = mike.LastName;
                bob.FirstName = "Michael Jr";
    
                Person mike3 = new Person();
                mike3 = mike;
    
                var mike2 = mike;
                mike2.FirstName = "Richard";
                mike.LastName = "Harris";
    
                Console.WriteLine
                    (string.Format("{0} {1} - {2} {3} - {4} {5} - {6} {7} ", 
                    mike.FirstName, mike.LastName, 
                    mike2.FirstName, mike2.LastName,
                    mike3.FirstName, mike3.LastName,
                    bob.FirstName, bob.LastName));
    
                Console.ReadLine();
            }
        }
    
        public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
    }

    Come out with:

    Richard Harris - Richard Harris - Richard Harris - Michael Jr Bolton
    I'm still looking for the answer

    Jannen Siahaan - Indonesia



    • Edited by humaNiT Saturday, May 19, 2012 12:53 AM
    Saturday, May 19, 2012 12:42 AM
  • Hi Emad,

    Here the answer, need to redefine myCustomer:

    originalCustomer = myCustomer;
    myCustomer = new Customer()                       // assume: Customer is a class
    myCustomer.FirstName = "New Name";

    Here my test, and please test also:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication4
    {
        class Program
        {
            static void Main(string[] args)
            {
                Person mike1 = new Person() { FirstName = "Michael", LastName = "Bolton" };
                Person bobby = mike1;
                mike1 = new Person() { FirstName = "Richard", LastName = "Harris" };
                var mike2 = bobby;
                Person mike3 = mike1;
                mike2.LastName = "Siahaan";
                Console.WriteLine(string.Format("mike1: {0} {1}", mike1.FirstName, mike1.LastName));
                Console.WriteLine(string.Format("mike2: {0} {1}", mike2.FirstName, mike2.LastName));
                Console.WriteLine(string.Format("mike3: {0} {1}", mike3.FirstName, mike3.LastName));
                Console.WriteLine(string.Format("bobby: {0} {1}", bobby.FirstName, bobby.LastName));
                Console.WriteLine();
            }
        }
        public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
    }

    Here the result:

    mike1: Richard Harris
    mike2: Michael Siahaan
    mike3: Richard Harris
    bobby: Michael Siahaan

    Have fun


    Jannen Siahaan - Indonesia

    Saturday, May 19, 2012 1:45 AM
  • thanks for all your help but by the way my question was about javascript not c# :-)

    www.emadibrahim.com

    Saturday, May 19, 2012 1:19 PM
  • Hi,

    I am not aware of a simpler solution. Please try to go through all members and copy them:

    var newCustomer = new Customer();
    newCustomer.LastName = originalCustomer.LastName;
    // Copy other members.
    // Now when you modify the copy, the original object will remain intact.
    newCustomer.FirstName = "New Name";

    Consider to write a function cloneCustomer to encapsulate the behavior.

    Best Regards,

    Ming Xu.


    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework

    Monday, May 21, 2012 7:20 AM
    Moderator
  • I guess no one is reading my posting...   This is the best answer so far and it is ONE LINE OF CODE....  You will have to reference jquery though.

    // Shallow copy
    var newObject = jQuery.extend({}, oldObject);

    // Deep copy
    var newObject = jQuery.extend(true, {}, oldObject);


    www.emadibrahim.com

    Monday, May 21, 2012 12:28 PM
  • Hi Emad,

    There is nothing Metro about the solution.  This is how javascript works.  You can simplify your code even more by defining your own extend function and applying it like this (no arguments except the object to copy:

    // my secret javascript library :-)

    var jeffQuery = { extend: function(objToCopy){ var copy = {}; for (var prop in objToCopy) { copy[prop] = objToCopy[prop]; } return copy; } } function btnClick(event) { txtContent.innerText = "clicked"; var newcustomer = { firstName: "Jeff", lastName: "Sanders" }; var copyCustomer = jeffQuery.extend(newcustomer); copyCustomer.firstName = "Jimmy"; txtContent.innerText = newcustomer.firstName; }

    -Jeff

    Jeff Sanders (MSFT)

    Tuesday, May 22, 2012 6:57 PM
    Moderator
  • Minor aside- since this is a Metro style app, you have ES5 support, which means you can use Object.getOwnPropertyNames (http://msdn.microsoft.com/en-us/library/ff688126(v=VS.94).aspx) to get non-enumerable properties if those are important to you.

    There is an interesting IE blog post that goes into how to do things like cloning, with ES5 code examples: http://blogs.msdn.com/b/ie/archive/2010/10/27/ecmascript-5-part-1-reusable-code.aspx

     

    Cheers,

    -Jeff

    Thursday, May 24, 2012 10:36 PM
  • Very nice Jeff!

    So we can re-write the clone to be:

    Object.clone = function (o) {
      var n = Object.create(Object.getPrototypeOf(o));
      var props = Object.getOwnPropertyNames(o);
      var pName;
      for (var p in props) {
        pName = props[p];
        Object.defineProperty(n, pName, Object.getOwnPropertyDescriptor(o, pName));  
      };
      return n;
    };

    and the sample code would be:

     function btnClick(event) {
            txtContent.innerText = "clicked";
            var newcustomer = { firstName: "Jeff", lastName: "Sanders" };
            var copyCustomer = Object.clone(newcustomer);
            copyCustomer.firstName = "Jimmy";
            txtContent.innerText = newcustomer.firstName;
        }

    -Jeff

    Jeff Sanders (MSFT)

    Friday, May 25, 2012 11:57 AM
    Moderator