How to Deep clone in javascript

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

提交回复
热议问题