在javascript中深层复制嵌套对象的数组

时间:2015-03-05 11:01:31

标签: javascript arrays deep-copy

我正在尝试在javascript中深层复制嵌套对象的数组。我的数组看起来像这样

var arr = [{name:"adam",age:"21"},
    {name:"freddie",age:"35",children:[{name:"mercury",age:"25"}]},
    {name:"jim",age:"35",children:[{name:"morrison",age:"25",children:[{name:"some", age:"40"}]}]}
    ];

我想对数组中的每个对象进行深层复制,我希望将arr的精确副本创建为不应该有对象引用的新数组。数组的深度也是未知的,即子数组可以达到任何级别。 我已经通过了这个链接 Copying of an array of objects to another Array without object reference in javascript(Deep copy)但这对我没有帮助。我用谷歌搜索并在jQuery中找到了一些解决方案,但这对我没有帮助,因为我不了解jQuery。

我也试过用递归来实现它,但那也不行 http://ideone.com/kJi5X3

我想在不使用jQuery或任何东西的情况下在javascript中完成它。我是JavaScript的新手,所以如果有任何库或简单的方法,我可能会错过。 请帮我解决这个问题。提前谢谢。

1 个答案:

答案 0 :(得分:28)

您有两个主要选择:

  1. 使用JSON.stringifyJSON.parse

    var copy = JSON.parse(JSON.stringify(original));
    

    但是我从来都不喜欢这样。往返文本往往效率低下,除非您编写替代者和复活者,否则它无法正确处理DateRegExpundefined等值。

  2. 使用递归函数,如下所示:

  3. var toString = Object.prototype.toString;
    function deepCopy(obj) {
        var rv;
    
        switch (typeof obj) {
            case "object":
                if (obj === null) {
                    // null => null
                    rv = null;
                } else {
                    switch (toString.call(obj)) {
                        case "[object Array]":
                            // It's an array, create a new array with
                            // deep copies of the entries
                            rv = obj.map(deepCopy);
                            break;
                        case "[object Date]":
                            // Clone the date
                            rv = new Date(obj);
                            break;
                        case "[object RegExp]":
                            // Clone the RegExp
                            rv = new RegExp(obj);
                            break;
                        // ...probably a few others
                        default:
                            // Some other kind of object, deep-copy its
                            // properties into a new object
                            rv = Object.keys(obj).reduce(function(prev, key) {
                                prev[key] = deepCopy(obj[key]);
                                return prev;
                            }, {});
                            break;
                    }
                }
                break;
            default:
                // It's a primitive, copy via assignment
                rv = obj;
                break;
        }
        return rv;
    }
    var a = [1, {foo: "bar"}, ['a', 'b'], new Date()];
    snippet.log(JSON.stringify(a));
    var b = deepCopy(a);
    snippet.log(JSON.stringify(b));
    <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
    <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

    请注意,上面使用的是所有现代浏览器中都存在的ES5功能,但不包括某些较旧的浏览器,如IE8。但是,对于旧版浏览器,上面使用的所有功能都可以进行填充。

    这不会试图处理自定义构造函数或保留数组中对象的原型;如果没有关于如何为复制操作调用这些构造函数的约定,这样做会使事情显着更复杂并且不可能完美。你可以通过分配相同的原型来接近,但这不会解释构造函数中的逻辑,特别是对于在其中设置为闭包的函数。