albert sh
albert sh

Reputation: 1193

How to copy between two existing objects in javascript

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.

Upvotes: 2

Views: 310

Answers (3)

Jimmy Breck-McKye
Jimmy Breck-McKye

Reputation: 3034

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.

Upvotes: 2

Lajos Arpad
Lajos Arpad

Reputation: 76436

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.

Upvotes: 0

Andrew
Andrew

Reputation: 7545

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)

Upvotes: 7

Related Questions