16

In reducers,we always use Object.assign({},state,newState) to save a state. But assign() doesn't support deepcopy,because this method only copy a reference of multi-level object. This is my code in program.

const menuListState={
 menuList: {},
 menuListLoading:false
}
function getMenuList(state=menuListState,action=defaultAction){
 switch(action.type){
  //menuList begin
  case actions.GET_MENULIST_SUCCESS:
      return Object.assign({},state,{
       menuList:action.data,
       menuListLoading:false
      });

  default:
   return state;
 }
}

The property menuList is a multi-level Object. And when action.data changes, will state.menuList be changed immediately before the method assign() work?

ThiagoSun
  • 177
  • 1
  • 1
  • 7

5 Answers5

32

You can use JSON.stringify to stringify an object, and use JSON.parse to parse your result string into an object, you will get your new object same with the one you want to deeply copy.

Example:

let copiedObject = JSON.parse(JSON.stringify(originalObject))
Vaibhav Singh
  • 932
  • 7
  • 20
passion
  • 1,250
  • 9
  • 15
  • I've heard that this is actually really fast because it is implemented natively – user3413723 Feb 20 '17 at 17:34
  • 1
    Whilst the answer is not some native React process, this process has been the accepted answer for similar things like Angular JS 1 for a long time (due to performance and brevity). Upvoted – mn. Apr 15 '17 at 11:49
  • 1
    Watch out for issues with dates roundtripping with this method. – Ian Michael Williams Feb 10 '18 at 03:42
  • 1
    Also, watch out for regex, they get replaced by empty strings – azhar22k May 25 '18 at 04:56
  • Yes, and so does the type of js function. – ThiagoSun Aug 31 '18 at 08:54
  • 4
    This only works if your object does not contain: `Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types` See https://stackoverflow.com/a/122704/5815054. Else use somehing linke `lodash.clonedeep`, see other answers. – hb0 Apr 21 '20 at 09:22
12

You may be interested in cloneDeep form lodash, used as follows:

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

Heres the npm package for just that method.

Jemar Jones
  • 1,491
  • 2
  • 21
  • 27
1

You can do, JSON serialisation,

var clone = JSON.parse(JSON.stringify(oldObjCopy));

but, its not recommended as, you may lose any Javascript, JSON property like Function or undefined.Those get ignored by JSON.stringify, causing them to be missed on the cloned object. Date object results into string. instead you can use easiest Lodash,

import cloneDeep from 'lodash/cloneDeep';
var clone = cloneDeep(oldObjCopy);
Ashish Kamble
  • 2,555
  • 3
  • 21
  • 29
1

Very interested this thread. HERE is my rough profiling in chrome. largeObj is about 15k chars

let i, t = new Date().getTime();
for(i=0;i<1000;i++) cloneDeep(largeObj)
console.log('clone', new Date().getTime() - t);

t = new Date().getTime();
for(i=0;i<1000;i++) JSON.parse(JSON.stringify(largeObj));
console.log('JSON', new Date().getTime() - t);

And the below is my result. "clone" won

clone 46
JSON 82
clone 42
JSON 87
clone 45
JSON 87
clone 46
JSON 85
clone 44
JSON 86
0

Sure if action.data is reference types (object, array,...), state.menuList will be changed immediately when you change action.data because they reference to the same value. It's just a normal functional of Javascript.

Caojs
  • 175
  • 7