Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS: Does Object.assign() create deep copy or shallow copy

People also ask

Does object assign copy object?

assign() The Object. assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.

Does copy () create a deep copy?

In this article, we learned what it means to shallow copy and to deep copy an object. We also learned that we can use the copy() method of the copy module to create a shallow copy, and the deepcopy() method to create a deep copy of the compound objects.

Does object spread do deep copy?

The spread operator makes deep copies of data if the data is not nested. When you have nested data in an array or object the spread operator will create a deep copy of the top most data and a shallow copy of the nested data.

What is the difference between object assign and object create?

Object. assign() provides shallow copying (Only properties and methods) and it will override the method and property declared. while Object. create() provides Deep copying provides prototype chain.


Forget about deep copy, even shallow copy isn't safe, if the object you're copying has a property with enumerable attribute set to false.

MDN :

The Object.assign() method only copies enumerable and own properties from a source object to a target object

take this example

var o = {};

Object.defineProperty(o,'x',{enumerable: false,value : 15});

var ob={}; 
Object.assign(ob,o);

console.log(o.x); // 15
console.log(ob.x); // undefined

By using Object.assign(), you are actually doing Shallow Copy of your object. Whenever we do an operation like assigning one object to other, we actually perform a shallow copy, i.e. if OBJ1 is an object, modifying it through another object which is OBJ2 will reflect changes in OBJ1 too.


It creates a shallow copy, according to this paragraph from MDN:

For deep cloning, we need to use other alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value.

For the purposes of redux, Object.assign() is sufficient because the state of a redux app only contains immutable values (JSON).


For small Data structures I see that JSON.stringify() and JSON.parse() work nice.

// store as JSON
var copyOfWindowLocation = JSON.stringify(window.location)
console.log("JSON structure - copy:", copyOfWindowLocation)
// convert back to Javascript Object
copyOfWindowLocation = JSON.parse(copyOfWindowLocation)
console.log("Javascript structure - copy:", copyOfWindowLocation)

Other answers are complicated.
Some don't answer the question at all.

Below worked for me

// orignal object with deep keys
var originalObject = {
    k1: "v1",
    k2: "v2",
    deepObj: {
        k3: "v3",
        k4: "v4"
    }
};

// make copies now
var copy1 = JSON.parse(JSON.stringify(originalObject));
var copy2 = JSON.parse(JSON.stringify(originalObject));

Hope that helps.


As mentioned above, Object.assign() will do a shallow clone, fail to copy the source object's custom methods, and fail to copy properties with enumerable: false.

Preserving methods and non-enumerable properties takes more code, but not much more.

This will do a shallow clone of an array or object, copying the source's methods and all properties:

function shallowClone(src) {
  let dest = (src instanceof Array) ? [] : {};

// duplicate prototypes of the source
  Object.setPrototypeOf(dest, Object.getPrototypeOf(src));

  Object.getOwnPropertyNames(src).forEach(name => {
    const descriptor = Object.getOwnPropertyDescriptor(src, name);
    Object.defineProperty(dest, name, descriptor);
  });
  return dest;
}

Example:

class Custom extends Object {
  myCustom() {}
}

const source = new Custom();
source.foo = "this is foo";
Object.defineProperty(source, "nonEnum", {
  value: "do not enumerate",
  enumerable: false
});
Object.defineProperty(source, "nonWrite", {
  value: "do not write",
  writable: false
});
Object.defineProperty(source, "nonConfig", {
  value: "do not config",
  configurable: false
});

let clone = shallowClone(source);

console.log("source.nonEnum:",source.nonEnum);
// source.nonEnum: "do not enumerate"
console.log("clone.nonEnum:", clone.nonEnum);
// clone.nonEnum: – "do not enumerate"

console.log("typeof source.myCustom:", typeof source.myCustom);
// typeof source.myCustom: – "function"
console.log("typeof clone.myCustom:", typeof clone.myCustom);
// typeof clone.myCustom: – "function"

jsfiddle