我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。

如何正确克隆JavaScript对象?


当前回答

由于mindeeavor指出要克隆的对象是一个“字面构造的”对象,因此解决方案可能是简单地多次生成对象,而不是克隆对象的实例:

function createMyObject()
{
    var myObject =
    {
        ...
    };
    return myObject;
}

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();

其他回答

好的,我知道它有很多答案,但没有人指出,EcmaScript5有赋值方法,在FF和Chrome上工作,它复制可枚举的,并且拥有财产和符号。

对象指定(Object Assign)

//
// creates 'clone' method on context object
//
//  var 
//     clon = Object.clone( anyValue );
//
!((function (propertyName, definition) {
    this[propertyName] = definition();
}).call(
    Object,
    "clone",
    function () {
        function isfn(fn) {
            return typeof fn === "function";
        }

        function isobj(o) {
            return o === Object(o);
        }

        function isarray(o) {
            return Object.prototype.toString.call(o) === "[object Array]";
        }

        function fnclon(fn) {
            return function () {
                fn.apply(this, arguments);
            };
        }

        function owns(obj, p) {
            return obj.hasOwnProperty(p);
        }

        function isemptyobj(obj) {
            for (var p in obj) {
                return false;
            }
            return true;
        }

        function isObject(o) {
            return Object.prototype.toString.call(o) === "[object Object]";
        }
        return function (input) {
            if (isfn(input)) {
                return fnclon(input);
            } else if (isobj(input)) {
                var cloned = {};
                for (var p in input) {
                    owns(Object.prototype, p)
                    || (
                        isfn(input[p])
                        && ( cloned[p] = function () { return input[p].apply(input, arguments); } )
                        || ( cloned[p] = input[p] )
                    );
                }
                if (isarray(input)) {
                    cloned.length = input.length;
                    "concat every filter forEach indexOf join lastIndexOf map pop push reduce reduceRight reverse shift slice some sort splice toLocaleString toString unshift"
                    .split(" ")
                    .forEach(
                      function (methodName) {
                        isfn( Array.prototype[methodName] )
                        && (
                            cloned[methodName] =
                            function () {
                                return Array.prototype[methodName].apply(cloned, arguments);
                            }
                        );
                      }
                    );
                }
                return isemptyobj(cloned)
                       ? (
                          isObject(input)
                          ? cloned
                          : input
                        )
                       : cloned;
            } else {
                return input;
            }
        };
    }
));
//

我之所以来到这个页面是因为同样的问题,但我既没有使用JQuery,也没有一个克隆方法适用于我自己的对象。

我知道我的答案与这个问题没有太大关系,因为这是一种不同的方法。我不使用克隆函数,而是使用创建函数。它对我来说有以下(不幸的是限制)目的:

我主要使用JSP生成的Javascript我一开始就知道必须生成哪个Object(在我的例子中,它是来自数据库的信息,只获取一次,需要在JS中更频繁地部署。

首先,我这样定义对象:

var obj= new Object();
obj.Type='Row';
obj.ID=1;
obj.Value='Blah blah';

现在我移动了所有的东西,比如:

function getObjSelektor(id_nummer,selected){
var obj = document.createElement("select");
obj.setAttribute("id","Selektor_"+id_nummer);
obj.setAttribute("name","Selektor");
obj.setAttribute("size","1");

var obj_opt_1 = document.createElement("option");
obj_opt_1.setAttribute("value","1");
if(1==selected)
    posopval_opt_1.setAttribute("selected","selected");
obj_opt_1.innerHTML="Blah blah";
obj.appendChild(obj_opt_1);

var obj_opt_2 = document.createElement("option");
obj_opt_2.setAttribute("value","2");
if(2==selected)
    obj_opt_2.setAttribute("selected","selected");
obj_opt_2.innerHTML="2nd Row";
obj.appendChild(obj_opt_2);

...

return obj;
}

并调用常规代码中的函数:

myDiv.getObjSelektor(getObjSelektor(anotherObject.ID));

正如所说,这是一种不同的方法,它为我的目的解决了我的问题。

我认为,在没有库的情况下,缓存的重复性是最好的。

被低估的WeakMap涉及到循环的问题,其中存储对新旧对象的引用可以帮助我们很容易地重建整个树。

我阻止了DOM元素的深度克隆,可能您不想克隆整个页面:)

function deepCopy(object) {
    const cache = new WeakMap(); // Map of old - new references

    function copy(obj) {
        if (typeof obj !== 'object' ||
            obj === null ||
            obj instanceof HTMLElement
        )
            return obj; // primitive value or HTMLElement

        if (obj instanceof Date) 
            return new Date().setTime(obj.getTime());

        if (obj instanceof RegExp) 
            return new RegExp(obj.source, obj.flags);

        if (cache.has(obj)) 
            return cache.get(obj);

        const result = obj instanceof Array ? [] : {};

        cache.set(obj, result); // store reference to object before the recursive starts

        if (obj instanceof Array) {
            for(const o of obj) {
                 result.push(copy(o));
            }
            return result;
        }

        const keys = Object.keys(obj); 

        for (const key of keys)
            result[key] = copy(obj[key]);

        return result;
    }

    return copy(object);
}

一些测试:

// #1
const obj1 = { };
const obj2 = { };
obj1.obj2 = obj2;
obj2.obj1 = obj1; // Trivial circular reference

var copy = deepCopy(obj1);
copy == obj1 // false
copy.obj2 === obj1.obj2 // false
copy.obj2.obj1.obj2 // and so on - no error (correctly cloned).

// #2
const obj = { x: 0 }
const clone = deepCopy({ a: obj, b: obj });
clone.a == clone.b // true

// #3
const arr = [];
arr[0] = arr; // A little bit weird but who cares
clone = deepCopy(arr)
clone == arr // false;
clone[0][0][0][0] == clone // true;

注意:我使用常量、for of循环、=>运算符和WeakMaps来创建更重要的代码。当前的浏览器支持此语法(ES6)

对克隆简单对象感兴趣:

JSON.parse(JSON.stringify(JSON_inoriginal));

来源:如何通过引用将JavaScript对象复制到新变量NOT?