How to Deep clone in javascript

前端 未结 19 1468
-上瘾入骨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:52

    This one, using circular reference, works for me

     //a test-object with circular reference :
     var n1 = {   id:0,   text:"aaaaa",   parent:undefined} 
     var n2 = {  id:1,   text:"zzzzz",   parent:undefined } 
     var o = { arr:[n1,n2],   parent:undefined } 
     n1.parent = n2.parent = o;
     var obj = {   a:1,   b:2,   o:o }
     o.parent = obj;
    
     function deepClone(o,output){ 
    
         if(!output) output = {};  
         if(o.______clone) return o.______clone;
         o.______clone = output.______clone = output;
    
       for(var z in o){
    
         var obj = o[z];
         if(typeof(obj) == "object") output[z] = deepClone(obj)
         else output[z] = obj; 
        }
    
       return output;
    }
    
    console.log(deepClone(obj));
    
    0 讨论(0)
  • 2020-11-22 02:55

    As others have noted on this and similar questions, cloning an "object", in the general sense, is dubious in JavaScript.

    However, there is a class of objects, which I call "data" objects, that is, those constructed simply from { ... } literals and/or simple property assignments or deserialized from JSON for which it is reasonable to want to clone. Just today I wanted to artificially inflate data received from a server by 5x to test what happens for a large data set, but the object (an array) and its children had to be distinct objects for things to function correctly. Cloning allowed me to do this to multiply my data set:

    return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));
    

    The other place I often end up cloning data objects is for submitting data back to the host where I want to strip state fields from the object in the data model before sending it. For example, I might want to strip all fields starting with "_" from the object as it is cloned.

    This is the code I ended up writing to do this generically, including supporting arrays and a selector to choose which members to clone (which uses a "path" string to determine context):

    function clone(obj,sel) {
        return (obj ? _clone("",obj,sel) : obj);
        }
    
    function _clone(pth,src,sel) {
        var ret=(src instanceof Array ? [] : {});
    
        for(var key in src) {
            if(!src.hasOwnProperty(key)) { continue; }
    
            var val=src[key], sub;
    
            if(sel) {
                sub+=pth+"/"+key;
                if(!sel(sub,key,val)) { continue; }
                }
    
            if(val && typeof(val)=='object') {
                if     (val instanceof Boolean) { val=Boolean(val);        }
                else if(val instanceof Number ) { val=Number (val);        }
                else if(val instanceof String ) { val=String (val);        }
                else                            { val=_clone(sub,val,sel); }
                }
            ret[key]=val;
            }
        return ret;
        }
    

    The simplest reasonable deep-clone solution, assuming a non-null root object and with no member selection is:

    function clone(src) {
        var ret=(src instanceof Array ? [] : {});
        for(var key in src) {
            if(!src.hasOwnProperty(key)) { continue; }
            var val=src[key];
            if(val && typeof(val)=='object') { val=clone(val);  }
            ret[key]=val;
            }
        return ret;
        }
    
    0 讨论(0)
  • 2020-11-22 02:55

    Avoid use this method

    let cloned = JSON.parse(JSON.stringify(objectToClone));
    

    Why? this method will convert 'function,undefined' to null

    const myObj = [undefined, null, function () {}, {}, '', true, false, 0, Symbol];
    
    const IsDeepClone = JSON.parse(JSON.stringify(myObj));
    
    console.log(IsDeepClone); //[null, null, null, {…}, "", true, false, 0, null]
    

    try to use deepClone function.There are several above

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

    The JSON.parse(JSON.stringify()) combination to deep copy Javascript objects is an ineffective hack, as it was meant for JSON data. It does not support values of undefined or function () {}, and will simply ignore them (or null them) when "stringifying" (marshalling) the Javascript object into JSON.

    A better solution is to use a deep copy function. The function below deep copies objects, and does not require a 3rd party library (jQuery, LoDash, etc).

    function copy(aObject) {
      if (!aObject) {
        return aObject;
      }
    
      let v;
      let bObject = Array.isArray(aObject) ? [] : {};
      for (const k in aObject) {
        v = aObject[k];
        bObject[k] = (typeof v === "object") ? copy(v) : v;
      }
    
      return bObject;
    }
    
    0 讨论(0)
  • 2020-11-22 03:00

    Lo-Dash, now a superset of Underscore.js, has a couple of deep clone functions:

    • _.cloneDeep(object)

    • _.cloneDeepWith(object, (val) => {if(_.isElement(val)) return val.cloneNode(true)})

      the second parameter is a function that is invoked to produce the cloned value.

    From an answer of the author himself:

    lodash underscore build is provided to ensure compatibility with the latest stable version of Underscore.

    0 讨论(0)
  • 2020-11-22 03:00

    I noticed that Map should require special treatment, thus with all suggestions in this thread, code will be:

    function deepClone( obj ) {
        if( !obj || true == obj ) //this also handles boolean as true and false
            return obj;
        var objType = typeof( obj );
        if( "number" == objType || "string" == objType ) // add your immutables here
            return obj;
        var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
        if( obj instanceof Map )
            for( var key of obj.keys() )
                result.set( key, deepClone( obj.get( key ) ) );
        for( var key in obj )
            if( obj.hasOwnProperty( key ) )
                result[key] = deepClone( obj[ key ] );
        return result;
    }
    
    0 讨论(0)
提交回复
热议问题