2

I have two objects that are the same type and I want to copy the content of one of them to the other.

const Invoice1 = new InvoiceModel(); 

const Invoice2 = new InvoiceModel();

now in order to have something like : Invoice2 = Invoice1

After reading :

How do I correctly clone a JavaScript object?

I tried to use any of below commands but all of them say that invoice2 is not defined at runtime:

 Invoice2 = { ...Invoice1 };  //OR

 Invoice2 = Object.assign({}, Invoice1);  //OR

 Invoice2 = JSON.parse(JSON.stringify(Invoice1));

finally I used this function to copy the content of objects by reading this article (https://medium.com/@Farzad_YZ/3-ways-to-clone-objects-in-javascript-f752d148054d):

function CopyObject(src, target) {
  for (let prop in src) {
    if (src.hasOwnProperty(prop)) {
      target[prop] = src[prop];
    }
  }
  return target;
}

I wonder is there any cleaner way to do that except using above function?

I have read many post regarding this issue but all of them create a new object.

20
  • i always use the spread operator ... Commented May 28, 2019 at 18:21
  • 2
    Object.assign(Invoice2, Invoice1) is the modern way Commented May 28, 2019 at 18:23
  • @danh you will need to use some polyfills because Object.assign is not supported in IE Commented May 28, 2019 at 18:24
  • You can use first two method only for shallow copies, you need to use 3rd one in case you want to do deep clone, there are many libraries which you can use if you want such as loadash Commented May 28, 2019 at 18:25
  • 1
    Because you can't reassign a const Commented May 28, 2019 at 18:30

3 Answers 3

7

I recommend creating a method in the prototype in InvoiceModel that does this automatically for you.

class InvoiceModel {
  constructor(num) {
    this.num = num
  }
  duplicate() {
    return Object.assign(Object.create(this), this)
  }
}

const obj1 = new InvoiceModel(10)
console.log(obj1.num)
const obj1Copy = obj1.duplicate()
console.log(obj1Copy.num)
console.log(obj1Copy === obj1)

Sign up to request clarification or add additional context in comments.

4 Comments

@albert sh - duplication will entail different things as soon as your classes stop representing simple data objects.
@Andrew, Thanks for your answer, I still cant use duplicate to assign to an existing variable, if you already craete : obj1copy = new InvoiceMode, how can you use duplicate as Obj1 and Obj1Copy are both global variables?
Assigning to existing variable names and creating copies of an existing object are two entirely different things. Maybe I am misinterpreting your question, but the reason why i console.log(obj1Copy === obj1) is to prove that they are separate entities. You can now modify one without affecting the other.
@JimmyBreck-McKye Yea, that's true. But based on OPs example, this will accomplish the same thing, only cleaner, which is what was requested
2

If the objects are just plain old data objects - with no methods or private state - you can just use a deep object clone method as specified here.

However, by the looks of things you are using classes with constructors, which implies you have methods and state. This is more tricky, because it suggests you may be relying on the constructor being re-run, e.g. to store private state in a closure, to allocate other resources, or rely on some kind of side effects. In that case you will need some kind of Invoice.prototype.clone method, that knows how to inject state into a new instance, and reruns the constructor function for the class - as per @andrew's answer.

I would avoid cloning objects with the syntax target = {...src}, which one commenter suggested. This will cause you trouble as soon as you have non-scalar reference members like sub-objects or arrays (as you will be copying pointers to the originals, not cloning their values). The same flaw applies to that CopyObject function you have picked up.

Comments

0

I have implemented a deep copier of objects, it does not override anything in the target option, but if you need that, you can achieve that as well:

var defaults = {
        options: {
                remove: true,
                enable: false,
                instance: {}
        },

        log: {
                warn: true,
                error: true
        }
};

var config = {
        options: {
                remove: false,
                instance: null
        }
};

function applyDefaults(d, t) {
    if ((typeof d !== "object") && (typeof d !== "array")) {
        return d;
    }

    if (t === undefined) {
        if (typeof d === "object") {
            t = {};
        } else if (typeof d === "array") {
            t = [];
        }
    }

    for (var key in d) {
        if (t[key] === undefined) {
            t[key] = d[key];
        } else {
            applyDefaults(d[key], t[key]);
        }
    }
    return t;
}

applyDefaults(defaults, config);
console.log(config);

However, this will not copy "private" stuff, not defined as members of this.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.