Deep Copy in Es6 Using the Spread Syntax

Deep copy in ES6 using the spread syntax

No such functionality is built-in to ES6. I think you have a couple of options depending on what you want to do.

If you really want to deep copy:

  1. Use a library. For example, lodash has a cloneDeep method.
  2. Implement your own cloning function.

Alternative Solution To Your Specific Problem (No Deep Copy)

However, I think, if you're willing to change a couple things, you can save yourself some work. I'm assuming you control all call sites to your function.

  1. Specify that all callbacks passed to mapCopy must return new objects instead of mutating the existing object. For example:

    mapCopy(state, e => {
    if (e.id === action.id) {
    return Object.assign({}, e, {
    title: 'new item'
    });
    } else {
    return e;
    }
    });

    This makes use of Object.assign to create a new object, sets properties of e on that new object, then sets a new title on that new object. This means you never mutate existing objects and only create new ones when necessary.

  2. mapCopy can be really simple now:

    export const mapCopy = (object, callback) => {
    return Object.keys(object).reduce(function (output, key) {
    output[key] = callback.call(this, object[key]);
    return output;
    }, {});
    }

Essentially, mapCopy is trusting its callers to do the right thing. This is why I said this assumes you control all call sites.

Object copy using Spread operator actually shallow or deep?

So, for this problem, you have to understand what is the shallow copy and deep copy.

Shallow copy is a bit-wise copy of an object which makes a new object by copying the memory address of the original object. That is, it makes a new object by which memory addresses are the same as the original object.

Deep copy, copies all the fields with dynamically allocated memory. That is, every value of the copied object gets a new memory address rather than the original object.

Now, what a spread operator does? It deep copies the data if it is not nested. For nested data, it deeply copies the topmost data and shallow copies of the nested data.

In your example,

const oldObj = {a: {b: 10}};
const newObj = {...oldObj};

It deep copy the top level data, i.e. it gives the property a, a new memory address, but it shallow copy the nested object i.e. {b: 10} which is still now referring to the original oldObj's memory location.

If you don't believe me check the example,

const oldObj = {a: {b: 10}, c: 2};const newObj = {...oldObj};
oldObj.a.b = 2; // It also changes the newObj `b` value as `newObj` and `oldObj`'s `b` property allocates the same memory address.oldObj.c = 5; // It changes the oldObj `c` but untouched at the newObj

console.log('oldObj:', oldObj);console.log('newObj:', newObj);
.as-console-wrapper {min-height: 100%!important; top: 0;}

Does Spread Syntax create a shallow copy or a deep copy?

A variable can contain either a value (in case of primitive values, like 1), or a reference (in case of objects, like { food: "pasta" }. Primitive types can only be copied, and since they contain no properties, the shallow/deep distinction does not exist.

If you considered references themselves as primitive values, b = a is a copy of a reference. But since JavaScript does not give you direct access to references (like C does, where the equivalent concept is a pointer), refering to copying a reference as "copy" is misleading and confusing. In context of JavaScript, "copy" is a copy of a value, and a reference is not considered a value.

For non-primitive values, there are three different scenarios:

  • Coreferences, as created by b = a, merely point to the same object; if you modify a in any way, b is affected the same way. Intuitively you'd say that whichever object you modify it is reflected in the copy, but it would be wrong: there is no copy, there is just one object. Regardless of which reference you access the object from, it is the same entity. It is like slapping Mr. Pitt, and wondering why Brad is mad at you — Brad and Mr. Pitt are the same person, not clones.

let a = {
food: "pasta",
contents: {
flour: 1,
water: 1
}
}
let b = a;
a.taste = "good";
a.contents.flour = 2;
console.log(b);

How to copy object methods in ES6

This:

class Test {
toString() {
return "This is a test object";
}
}

does not define any object method strictly speaking. It rather defines class methods.

You need to attach methods directly to the object as "own properties" in order the spread to copy them:

class Test {  constructor() {    // define toString as a method attached directly to    // the object    this.toString = function() {      return "This is a test object";    }  }}
let test = new Test();let test2 = { ...test };
console.log(String(test));console.log(String(test2));

Syntax for deep copying an array with the spread operator

For each nested array, replace it with [...originalArrayReference]. If you have to replace particular indicies, slice the outer array before and after that index first:

const array1 = [['a'], 'b', 'c'];    const array2  = [[...array1[0]], ...array1.slice(1)];
//Modify the nested 2nd arrayarray2[0].push('pushed');
console.log(array1);console.log(array2);

Quick question about ES6 spread operator on objects

Objects cannot have duplicate keys. If you assign a key to an object when that object already has said key, or write an object initializer with duplicate keys, the prior value at that key will be overwritten:

const obj = {  foo: 'foo',  bar: 'bar',};
obj.foo = 'new';console.log(obj);

ES6 object cloning using spread operator is modifying input too

Spread operator does shallow cloning same as Object.assign()

Shallow-cloning (excluding prototype) or merging of objects is now
possible using a shorter syntax than Object.assign().

Spread operator

An example to understand spread operator and shallow cloning.

let obj = { 'a': { 'b' : 1 },'c': 2}
let copy = {...obj}
copy.c = 'changes only in copy' //shallow-cloned copy.a.b = 'changed' // still reference
console.log('original\n',obj)console.log('\ncopy',copy)

Does Spreading create shallow copy?

In your case a shallow copy and deep copy are the same. For an array containing only primitives, they will always be identical. You'll only notice the difference when your array contains other objects.

Javascript is pass by value, so when an array is shallow copied (such as by using spread), each value in the original array is copied to the new array. In the case of a primitive, the value is copied directly and changes made to it have no effect on the original.

However, when the array contains objects, each value is itself a reference to something else. So even though the reference has been copied to a new array, it still points to the same thing as the reference in the original array. So while mutating the new array will not change the original, mutating the elements of the array will affect the original.

Here's an example:

const objArray = [{foo: "bar"}];const shallowCopy = [...objArray];
// Changing the array itself does not change the orignal. Note the// original still only has one item, but the copy has two:shallowCopy.push({foo: "baz"});console.log("objArray after push:", objArray);console.log("shallowCopy after push:", shallowCopy);
// However, since shallowCopy[0] is a reference pointing to the same object// as objArray[0], mutating either will change the other:shallowCopy[0].foo = "something else";console.log("objArray after mutation:", objArray);console.log("shallowCopy after mutation:", shallowCopy);


Related Topics



Leave a reply



Submit