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

Deep copying array of nested objects in javascript

本问题已经有最佳答案,请猛点这里访问。

我尝试在javascript中深度复制嵌套对象的数组。我的阵列像这样

1
2
3
4
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的精确副本创建到不应该具有对象引用的新数组中。数组的深度也是未知的,即子数组可以达到任何级别。我查过这个链接将一个对象数组复制到另一个数组,但在javascript中没有对象引用(深度复制),但这对我没有帮助。我在网上搜索并在jquery中找到了一些解决方案,但这对我没有帮助,因为我不知道jquery。

我还尝试用递归实现它,但这也不起作用。http://ideone.com/kji5x3

我只想在不使用jquery或任何东西的情况下用javascript来完成它。我不熟悉JavaScript,所以如果有任何库或简单的方法可以做到这一点,我可能会错过。请帮我解决这个问题。事先谢谢。


您有两个主要选项:

  • 使用JSON.stringifyJSON.parse

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

    但我从来都不喜欢。在最好的情况下,通过文本的往返是无效的,并且它不会正确地处理DateRegExpundefined等值,除非您编写了替换器和恢复器。

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

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    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));
    1
    2
    <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
    <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js">

    请注意,上面使用的ES5功能在所有的现代浏览器上都存在,但不是一些老的浏览器,如IE8。但是,对于较旧的浏览器,上面使用的所有功能都可以是多段填充的。

    这并不意味着要处理定制的构造函数函数或保存数组中对象的原型;这样做会使事情变得非常复杂,而且如果没有一个如何为复制操作调用这些构造函数的约定,就不可能实现完美。您可以通过分配相同的原型来接近它,但这不能解释构造函数函数中的逻辑,特别是对于在其中设置为闭包的函数。