JavaScript中的克隆对象

这个问题在这里已经有了答案:

  • 我如何正确克隆一个JavaScript对象? 54个答案

  • 这将不会被引用

    <script>
        var obj = 
        {
            name: 'abc',
            age: '30'
        };
    
        var objTwo = {};
    
        for( var i in obj )
        {
            objTwo[i] = obj[i];
        }
    </script>
    

    查看小提琴


    我会用jQuery来做到这一点:

    var obj1 = {
         name: "abc",
         age: 20    
    }
    
    console.log(obj1);
    
    var obj2 = $.extend({}, obj1, {});
    console.log(obj2);
    
    obj2.age = 1;
    console.log(obj2);
    
    console.log(obj1);
    

    如果你只需要克隆简单的对象,简单地做

    JSON.parse (JSON.stringify (obj))

    就足够了。

    但是,这显然不适用于所有情况,因为JSON.stringify无法处理循环引用并删除函数。

    所以如果你想超越这个范围,事情会变得更加复杂,你必须依靠一些实用程序库或需要实现自己的深度克隆方法。

    这是一个预计要进行克隆的深度级别的示例实现。

    (function (Object, Array) {
        function cloneObject(deep, scope, clonedScope) {
            var type = typeof this,
                clone = {},
                isCR = -1;
    
            deep = Number(deep) || 0;
            scope = scope || [];
            clonedScope = clonedScope || [];
    
            if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
                throw new TypeError("Unexpected input");
            }
            //If we find a primitive, we reeturn its value.
            if (type !== "object") {
                return this.valueOf();
            }
    
            scope.push(this);
            clonedScope.push(clone);
    
            if (0 === deep) { //If we reached the recursion limit, we can perform a shallow copy
                for (var prop in this) {
                    clone[prop] = this[prop];
                }
            } else { //Otherwise we need to make some checks first.
                for (var prop in this) {
                    if ((isCR = scope.indexOf(this[prop])) > -1) { //If we find a circular reference, we want create a new circular reference to the cloned version.
                        clone[prop] = clonedScope[isCR];
                    } else if (typeof this[prop] !== "undefined" && this[prop] !== null) { //Otherwise continue cloning.
                        clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone(deep - 1, scope, clonedScope)); //If we find a non object, we can directly assign it. Otherwise we need to recursively call the clone function, counting down the limit, and injecting the scopeArrays, to find circular references.
                    } else { //If the property is undefined or null, assign it as such.
                        clone[prop] = this[prop];
                    }
                }
            }
    
            scope.pop(); //If we leave a recursion leve, we remove the current object from the list.
            clonedScope.pop();
    
            return clone;
        }
    
    
        function cloneArray(deep, scope, clonedScope) {
            var clone = [];
    
            deep = Number(deep) || 0;
    
            scope = scope || [];
            clonedScope = clonedScope || [];
    
            if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
                throw new TypeError("Unexpected input");
            }
    
    
            scope.push(this);
            clonedScope.push(this);
    
            if (0 === deep) clone = this.concat();
            else this.forEach(function (e) {
                if ((isCR = scope.indexOf(e)) > -1) {
                    clone.push(clonedScope[isCR]);
                } else if (typeof e !== "undefined" && e !== null) {
                    clone.push((typeof e !== "object" ? e : e.clone(deep - 1, scope, clonedScope)));
                } else {
                    clone.push(e);
                }
            });
    
            scope.pop();
            clonedScope.pop();
    
            return clone;
        }
    
        Object.defineProperty(Object.prototype, "clone", {
            enumerable: false,
            value: cloneObject
        });
    
        Object.defineProperty(Array.prototype, "clone", {
            enumerable: false,
            value: cloneArray
        });
    
    })(Object, Array);
    

    请注意,扩展内置原型通常是不被接受的,但是我决定这样做,以避免额外的类型检查,并将数组和对象的逻辑分开多一点。 这可以轻松地重构为普通函数

    一些测试来检查我们确实有新的参考。

    var first = {
        a: {
            b: "b",
            c: {
    
            }
        },
        b: "asd",
        c: [{}],
        d: undefined,
        e: null,
        f: function a() {} //functions keep their original reference..
    };
    
    first.a.c.a = first.a; //Circular object reference
    first.c.push(first.c); //Circular array reference
    
    var second = first.clone(Infinity);
    
    console.log(second, second.a === second.a.c.a, first.a !== second.a.c.a); //..., true, true.
    

    可能还有很多需要改进的空间,我特别不喜欢范围和cloneScope被注入的方式。 如果任何人有更好的想法找到并重新连接循环引用,我很乐意更新答案

    这也是一个小提琴。

    链接地址: http://www.djcxy.com/p/24763.html

    上一篇: Clone object in JavaScript

    下一篇: Assign value not reference in javascript