Full-stack Web Technologies

CHAPTER 7
Copying objects

Copying Values

In Javascript one can think that objects are separate from variables. A variable groucho doesn't directly "contain" the object, it just references it, so the object is stored somewhere else:

let groucho = { about: "I am a Marx", funny: true };
An image showing a variable pointing to the value it contains, which are separated things

When we assign one variable to another, the object that is referenced is not copied, only the reference is (the pointer or memory address). So this initialization

let chicco = groucho;

produces this result

An image showing two variables pointing to the same object

Copying objects by hand

To copy an object by hand, we can write a loop (a for-in) to copy all properties:

let copy = {};
for (const field in object) {
  copy[field] = object[field];
}

This is called a shallow copy since the fields of object are not copied, only their references are copied.

A special function Object.assign makes this process easier. It receives an object as a first argument (this is the target) and assigns to it all fields of the second argument:

let copy = Object.assign({}, object);

Merging objects

If we want to merge two objects (take all fields of all of them), we can call Object.assign with more than 2 arguments:

let model = { brand: "Tesla", model: "X" };
let config = { color: "red", battery: "90kWh" };
Object.assign({}, model, config);
// -> { brand: "Tesla", model: "X", color: "red", battery: "90kWh" }

Copying with spread

The same can be accomplished with the spread operator ..., which inserts all fields of an object into a new one:

let chicco = { ...groucho };

To copy many objects, we can also use spread many times:

let car = { ...model, ...config };

If any field is explicitly initialized, it will overwrite any fields coming from the spread:

let car = { ...model, ...config, model: "Y" };
// -> { brand: "Tesla", model: "Y", color: "red", battery: "90kWh" }

Deep Copy

Whenever we need a deep copy, a function called structuredClone will do it for us. This function clones the top object and any object inside it (the whole tree):

const obj = { a: 1, b: true, c: { d: null, f: "hi", e: [1, 2, 3] } };
const clone = structuredClone(obj);
console.log(obj === clone); // false (different objects)
console.log(clone);
// { a: 1, b: true, c: { d: null, f: 'hi', e: [ 1, 2, 3 ] } }