Deep copy in ES6 using the spread syntax

。_饼干妹妹 提交于 2019-11-27 18:54:47

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.

Instead use this for deep copy

var newObject = JSON.parse(JSON.stringify(oldObject))

var oldObject = {
  name: 'A',
  address: {
    street: 'Station Road',
    city: 'Pune'
  }
}
var newObject = JSON.parse(JSON.stringify(oldObject));

newObject.address.city = 'Delhi';
console.log('newObject');
console.log(newObject);
console.log('oldObject');
console.log(oldObject);
Mina Luke

From MDN

Note: Spread syntax effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays as the following example shows (it's the same with Object.assign() and spread syntax).

Personally, I suggest using Lodash's cloneDeep function for multi-level object/array cloning.

Here is a working example:

const arr1 = [{ 'a': 1 }];

const arr2 = [...arr1];

const arr3 = _.clone(arr1);

const arr4 = arr1.slice();

const arr5 = _.cloneDeep(arr1);

const arr6 = [...{...arr1}]; // a bit ugly syntax but it is working!


// first level
console.log(arr1 === arr2); // false
console.log(arr1 === arr3); // false
console.log(arr1 === arr4); // false
console.log(arr1 === arr5); // false
console.log(arr1 === arr6); // false

// second level
console.log(arr1[0] === arr2[0]); // true
console.log(arr1[0] === arr3[0]); // true
console.log(arr1[0] === arr4[0]); // true
console.log(arr1[0] === arr5[0]); // false
console.log(arr1[0] === arr6[0]); // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

I often use this:

function deepCopy(obj) {
    if(typeof obj !== 'object' || obj === null) {
        return obj;
    }

    if(obj instanceof Date) {
        return new Date(obj.getTime());
    }

    if(obj instanceof Array) {
        return obj.reduce((arr, item, i) => {
            arr[i] = deepCopy(item);
            return arr;
        }, []);
    }

    if(obj instanceof Object) {
        return Object.keys(obj).reduce((newObj, key) => {
            newObj[key] = deepCopy(obj[key]);
            return newObj;
        }, {})
    }
}
function deepclone(obj) {
    let newObj = {};

    if (typeof obj === 'object') {
        for (let key in obj) {
            let property = obj[key],
                type = typeof property;
            switch (type) {
                case 'object':
                    if( Object.prototype.toString.call( property ) === '[object Array]' ) {
                        newObj[key] = [];
                        for (let item of property) {
                            newObj[key].push(this.deepclone(item))
                        }
                    } else {
                        newObj[key] = deepclone(property);
                    }
                    break;
                default:
                    newObj[key] = property;
                    break;

            }
        }
        return newObj
    } else {
        return obj;
    }
}
// use: clone( <thing to copy> ) returns <new copy>
// untested use at own risk
function clone(o, m){
  // return non object values
  if('object' !==typeof o) return o
  // m: a map of old refs to new object refs to stop recursion
  if('object' !==typeof m || null ===m) m =new WeakMap()
  var n =m.get(o)
  if('undefined' !==typeof n) return n
  // shallow/leaf clone object
  var c =Object.getPrototypeOf(o).constructor
  // TODO: specialize copies for expected built in types i.e. Date etc
  switch(c) {
    // shouldn't be copied, keep reference
    case Boolean:
    case Error:
    case Function:
    case Number:
    case Promise:
    case String:
    case Symbol:
    case WeakMap:
    case WeakSet:
      n =o
      break;
    // array like/collection objects
    case Array:
      m.set(o, n =o.slice(0))
      // recursive copy for child objects
      n.forEach(function(v,i){
        if('object' ===typeof v) n[i] =clone(v, m)
      });
      break;
    case ArrayBuffer:
      m.set(o, n =o.slice(0))
      break;
    case DataView:
      m.set(o, n =new (c)(clone(o.buffer, m), o.byteOffset, o.byteLength))
      break;
    case Map:
    case Set:
      m.set(o, n =new (c)(clone(Array.from(o.entries()), m)))
      break;
    case Int8Array:
    case Uint8Array:
    case Uint8ClampedArray:
    case Int16Array:
    case Uint16Array:
    case Int32Array:
    case Uint32Array:
    case Float32Array:
    case Float64Array:
      m.set(o, n =new (c)(clone(o.buffer, m), o.byteOffset, o.length))
      break;
    // use built in copy constructor
    case Date:
    case RegExp:
      m.set(o, n =new (c)(o))
      break;
    // fallback generic object copy
    default:
      m.set(o, n =Object.assign(new (c)(), o))
      // recursive copy for child objects
      for(c in n) if('object' ===typeof n[c]) n[c] =clone(n[c], m)
  }
  return n
}
const cloneData = (dataArray) => {
    newData= []
    dataArray.forEach((value) => {
        newData.push({...value})
    })
    return newData
}
  • a = [{name:"siva"}, {name:"siva1"}] ;
  • b = myCopy(a)
  • b === a // false`
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!