Shallow copy
A shallow copy of an object is a copy whose properties share the same references (point to the same underlying values) as those of the source object from which the copy was made. As a result, when you change either the source or the copy, you may also cause the other object to change too. That behavior contrasts with the behavior of a deep copy, in which the source and copy are completely independent.
Shallow copying is usually implemented as such:
- A new object of the same type is created. The prototype chain is nearly always preserved. For example, deep copying a
Mapshould result in aMapand not something else. - For each own property of the original object, a property with the same key is defined on the new object.
- Each new property's value is set to the same reference as the original property's value. If the property's value is a primitive, no copying is done.
- Any data that's not exposed as properties (such as
Map) is ported over, but without copying any object references inside the data, provided that the implementation recognizes the object type and knows how to retrieve and set the data.
Note that because JavaScript has no built-in mechanism that performs a generic shallow copy (the existing ones only assume specific object types like plain objects or arrays), library implementations often diverge on technical details, such as:
- Whether non-enumerable or symbol properties are copied
- Whether property descriptors are copied
- Whether accessor properties are copied as accessors
- What data structures support copying non-property data
The copy of an object whose properties all have primitive values fits the definition of both a deep copy and a shallow copy. It is somewhat useless to talk about the depth of such a copy, though, because it has no nested properties and we usually talk about deep copying in the context of mutating nested properties.
For shallow copies, only the top-level properties are copied, not the values of nested objects. Therefore:
- Re-assigning top-level properties of the copy does not affect the source object.
- Re-assigning nested object properties of the copy does affect the source object.
In JavaScript, all standard built-in object-copy operations (spread syntax, Array.prototype.concat(), Array.prototype.slice(), Array.from(), and Object.assign()) create shallow copies rather than deep copies.
Consider the following example, in which an ingredientsList array object is created, and then an ingredientsListCopy object is created by copying that ingredientsList object.
const ingredientsList = ["noodles", { list: ["eggs", "flour", "water"] }];
const ingredientsListCopy = Array.from(ingredientsList);
console.log(ingredientsListCopy);
// ["noodles",{"list":["eggs","flour","water"]}]
Re-assigning the value of a nested property will be visible in both objects.
ingredientsListCopy[1].list = ["rice flour", "water"];
console.log(ingredientsList[1].list);
// Array [ "rice flour", "water" ]
Re-assigning the value of a top-level property (the 0 index in this case) will only be visible in the changed object.
ingredientsListCopy[0] = "rice noodles";
console.log(ingredientsList[0]); // noodles
console.log(JSON.stringify(ingredientsListCopy));
// ["rice noodles",{"list":["rice flour","water"]}]
console.log(JSON.stringify(ingredientsList));
// ["noodles",{"list":["rice flour","water"]}]
See also
- Related glossary terms: