Cloning: what's the fastest alternative to JSON.parse(JSON.stringify(x))?

前端 未结 3 1994
青春惊慌失措
青春惊慌失措 2021-01-30 13:21

What\'s the fastest alternative to

JSON.parse(JSON.stringify(x))

There must be a nicer/built-in way to perform a deep clone on objects/arrays,

3条回答
  •  孤独总比滥情好
    2021-01-30 14:00

    No, there is no build in way to deep clone objects.

    And deep cloning is a difficult and edgey thing to deal with.

    Lets assume that a method deepClone(a) should return a "deep clone" of b.

    Now a "deep clone" is an object with the same [[Prototype]] and having all the own properties cloned over.

    For each clone property that is cloned over, if that has own properties that can be cloned over then do so, recursively.

    Of course were keeping the meta data attached to properties like [[Writable]] and [[Enumerable]] in-tact. And we will just return the thing if it's not an object.

    var deepClone = function (obj) {
        try {
            var names = Object.getOwnPropertyNames(obj);
        } catch (e) {
            if (e.message.indexOf("not an object") > -1) {
                // is not object
                return obj;
            }    
        }
        var proto = Object.getPrototypeOf(obj);
        var clone = Object.create(proto);
        names.forEach(function (name) {
            var pd = Object.getOwnPropertyDescriptor(obj, name);
            if (pd.value) {
                pd.value = deepClone(pd.value);
            }
            Object.defineProperty(clone, name, pd);
        });
        return clone;
    };
    

    This will fail for a lot of edge cases.

    Live Example

    As you can see you can't deep clone objects generally without breaking their special properties (like .length in array). To fix that you have to treat Array seperately, and then treat every special object seperately.

    What do you expect to happen when you do deepClone(document.getElementById("foobar")) ?

    As an aside, shallow clones are easy.

    Object.getOwnPropertyDescriptors = function (obj) {
        var ret = {};
        Object.getOwnPropertyNames(obj).forEach(function (name) {
            ret[name] = Object.getOwnPropertyDescriptor(obj, name);
        });
        return ret;
    };
    
    var shallowClone = function (obj) {
        return Object.create(
            Object.getPrototypeOf(obj),
            Object.getOwnPropertyDescriptors(obj)
        );
    };
    

提交回复
热议问题