How to Deep clone in javascript

前端 未结 19 1467
-上瘾入骨i
-上瘾入骨i 2020-11-22 02:06

How do you deep clone a JavaScript object?

I know there are various functions based on frameworks like JSON.parse(JSON.stringify(o)) and $.extend(t

相关标签:
19条回答
  • 2020-11-22 02:36

    The Underscore.js contrib library library has a function called snapshot that deep clones an object

    snippet from the source:

    snapshot: function(obj) {
      if(obj == null || typeof(obj) != 'object') {
        return obj;
      }
    
      var temp = new obj.constructor();
    
      for(var key in obj) {
        if (obj.hasOwnProperty(key)) {
          temp[key] = _.snapshot(obj[key]);
        }
      }
    
      return temp;
    }
    

    once the library is linked to your project, invoke the function simply using

    _.snapshot(object);
    
    0 讨论(0)
  • 2020-11-22 02:37

    var newDate = new Date(this.oldDate); I was passing oldDate to function and generating newDate from this.oldDate, but it was changing this.oldDate also.So i used that solution and it worked.

    0 讨论(0)
  • 2020-11-22 02:41

    Here is an ES6 function that will also work for objects with cyclic references:

    function deepClone(obj, hash = new WeakMap()) {
        if (Object(obj) !== obj) return obj; // primitives
        if (hash.has(obj)) return hash.get(obj); // cyclic reference
        const result = obj instanceof Set ? new Set(obj) // See note about this!
                     : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => 
                                            [key, deepClone(val, hash)])) 
                     : obj instanceof Date ? new Date(obj)
                     : obj instanceof RegExp ? new RegExp(obj.source, obj.flags)
                     // ... add here any specific treatment for other classes ...
                     // and finally a catch-all:
                     : obj.constructor ? new obj.constructor() 
                     : Object.create(null);
        hash.set(obj, result);
        return Object.assign(result, ...Object.keys(obj).map(
            key => ({ [key]: deepClone(obj[key], hash) }) ));
    }
    
    // Sample data
    var p = {
      data: 1,
      children: [{
        data: 2,
        parent: null
      }]
    };
    p.children[0].parent = p;
    
    var q = deepClone(p);
    
    console.log(q.children[0].parent.data); // 1

    A note about Sets and Maps

    How to deal with the keys of Sets and Maps is debatable: those keys are often primitives (in which case there is no debate), but they can also be objects. In that case the question becomes: should those keys be cloned?

    One could argue that this should be done, so that if those objects are mutated in the copy, the objects in the original are not affected, and vice versa.

    On the other hand one would want that if a Set/Map has a key, this should be true in both the original and the copy -- at least before any change is made to either of them. It would be strange if the copy would be a Set/Map that has keys that never occurred before (as they were created during the cloning process): surely that is not very useful for any code that needs to know whether a given object is a key in that Set/Map or not.

    As you notice, I am more of the second opinion: the keys of Sets and Maps are values (maybe references) that should remain the same.

    Such choices will often also surface with other (maybe custom) objects. There is no general solution, as much depends on how the cloned object is expected to behave in your specific case.

    0 讨论(0)
  • 2020-11-22 02:43

    The below function is most efficient way to deep clone javascript objects.

    function deepCopy(obj){
        if (!obj || typeof obj !== "object") return obj;
    
        var retObj = {};
    
        for (var attr in obj){
            var type = obj[attr];
    
            switch(true){
                case (type instanceof Date):
                    var _d = new Date();
                    _d.setDate(type.getDate())
                    retObj[attr]= _d;
                    break;
    
                case (type instanceof Function):
                    retObj[attr]= obj[attr];
                    break;
    
                case (type instanceof Array):
                    var _a =[];
                    for (var e of type){
                        //_a.push(e);
                        _a.push(deepCopy(e));
                    }
                    retObj[attr]= _a;
                    break;
    
                case (type instanceof Object):
                    var _o ={};
                    for (var e in type){
                        //_o[e] = type[e];
                        _o[e] = deepCopy(type[e]);
                    }
                    retObj[attr]= _o;
                    break;
    
                default:
                    retObj[attr]= obj[attr];
            }
        }
        return retObj;
    }
    
    var obj = {
        string: 'test',
        array: ['1'],
        date: new Date(),
        object:{c: 2, d:{e: 3}},
        function: function(){
            return this.date;
        }
    };
    
    var copyObj = deepCopy(obj);
    
    console.log('object comparison', copyObj === obj); //false
    console.log('string check', copyObj.string === obj.string); //true
    console.log('array check', copyObj.array === obj.array); //false
    console.log('date check', copyObj2.date === obj.date); //false
    console.log('object check', copyObj.object === obj.object); //false
    console.log('function check', copyObj.function() === obj.function()); //true
    
    0 讨论(0)
  • 2020-11-22 02:45

    This solution will avoid recursion problems when using [...target] or {...target}

    function shallowClone(target) {
      if (typeof a == 'array') return [...target]
      if (typeof a == 'object') return {...target}
      return target
    }
    
    /* set skipRecursion to avoid throwing an exception on recursive references */
    /* no need to specify refs, or path -- they are used interally */
    function deepClone(target, skipRecursion, refs, path) {
      if (!refs) refs = []
      if (!path) path = ''
      if (refs.indexOf(target) > -1) {
        if (skipRecursion) return null
        throw('Recursive reference at ' + path)
      }
      refs.push(target)
      let clone = shallowCopy(target)
      for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
      return clone
    }
    
    0 讨论(0)
  • 2020-11-22 02:47

    This is the deep cloning method I use, I think it Great, hope you make suggestions

    function deepClone (obj) {
        var _out = new obj.constructor;
    
        var getType = function (n) {
            return Object.prototype.toString.call(n).slice(8, -1);
        }
    
        for (var _key in obj) {
            if (obj.hasOwnProperty(_key)) {
                _out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
            }
        }
        return _out;
    }
    
    0 讨论(0)
提交回复
热议问题