如何正确地克隆JavaScript对象?

时间:2022-10-30 15:08:22

I have an object, x. I'd like to copy it as object y, such that changes to y do not modify x. I realized that copying objects derived from built-in JavaScript objects will result in extra, unwanted properties. This isn't a problem, since I'm copying one of my own, literal-constructed objects.

我有一个对象,x,我想把它复制成对象y,这样对y的改变不会改变x,我意识到从内置的JavaScript对象中复制的对象会导致额外的,不需要的属性。这并不是问题,因为我正在复制我自己的、基于文本的对象。

How do I correctly clone a JavaScript object?

如何正确地克隆JavaScript对象?

53 个解决方案

#1


1235  

Updated answer

Just use Object.assign() as suggested here

只要使用Object.assign()就像这里建议的那样。


Outdated answer

To do this for any object in JavaScript will not be simple or straightforward. You will run into the problem of erroneously picking up attributes from the object's prototype that should be left in the prototype and not copied to the new instance. If, for instance, you are adding a clone method to Object.prototype, as some answers depict, you will need to explicitly skip that attribute. But what if there are other additional methods added to Object.prototype, or other intermediate prototypes, that you don't know about? In that case, you will copy attributes you shouldn't, so you need to detect unforeseen, non-local attributes with the hasOwnProperty method.

对于JavaScript中的任何对象,这样做都不是简单或直接的。您将遇到错误地从对象的原型中获取属性的问题,这些属性应该留在原型中,而不是复制到新实例中。例如,如果您正在为对象添加克隆方法。原型,正如一些回答所描述的那样,您需要显式地跳过该属性。但是如果有其他附加的方法添加到对象中会怎么样呢?原型,或者其他的中间原型,你不知道?在这种情况下,您将复制不应该复制的属性,因此您需要使用hasOwnProperty方法检测未预见的非本地属性。

In addition to non-enumerable attributes, you'll encounter a tougher problem when you try to copy objects that have hidden properties. For example, prototype is a hidden property of a function. Also, an object's prototype is referenced with the attribute __proto__, which is also hidden, and will not be copied by a for/in loop iterating over the source object's attributes. I think __proto__ might be specific to Firefox's JavaScript interpreter and it may be something different in other browsers, but you get the picture. Not everything is enumerable. You can copy a hidden attribute if you know its name, but I don't know of any way to discover it automatically.

除了不可枚举的属性之外,当您试图复制具有隐藏属性的对象时,您会遇到更棘手的问题。例如,prototype是函数的一个隐藏属性。另外,一个对象的原型与属性__proto__一起被引用,它也是隐藏的,并且不会被一个for/in循环复制到源对象的属性中。我认为__proto__可能是Firefox的JavaScript解释器所特有的,它可能在其他浏览器中有所不同,但是你可以看到它。并不是所有的。如果你知道它的名字,你可以复制一个隐藏的属性,但是我不知道有什么方法可以自动发现它。

Yet another snag in the quest for an elegant solution is the problem of setting up the prototype inheritance correctly. If your source object's prototype is Object, then simply creating a new general object with {} will work, but if the source's prototype is some descendant of Object, then you are going to be missing the additional members from that prototype which you skipped using the hasOwnProperty filter, or which were in the prototype, but weren't enumerable in the first place. One solution might be to call the source object's constructor property to get the initial copy object and then copy over the attributes, but then you still will not get non-enumerable attributes. For example, a Date object stores its data as a hidden member:

另一个追求优雅解决方案的障碍是正确设置原型继承的问题。如果你的源对象的原型对象,然后简单地创建一个新的通用对象用{ }将工作,但如果源的原型对象的一些后代,那么你将要错过了其他成员的原型,你跳过使用hasOwnProperty过滤器,或在原型,但没有可在第一时间。一个解决方案可能是调用源对象的构造函数来获取初始的复制对象,然后复制这些属性,但是您仍然不会得到不可枚举的属性。例如,Date对象将其数据存储为隐藏成员:

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
    var d2 = clone(d1);
    alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
}, 5000);

The date string for d1 will be 5 seconds behind that of d2. A way to make one Date the same as another is by calling the setTime method, but that is specific to the Date class. I don't think there is a bullet-proof general solution to this problem, though I would be happy to be wrong!

d1的日期字符串将比d2晚5秒。使一个日期与另一个日期相同的方法是调用setTime方法,但这是特定于日期类的。我不认为这个问题有一个防弹一般的解决方案,尽管我很高兴错了!

When I had to implement general deep copying I ended up compromising by assuming that I would only need to copy a plain Object, Array, Date, String, Number, or Boolean. The last 3 types are immutable, so I could perform a shallow copy and not worry about it changing. I further assumed that any elements contained in Object or Array would also be one of the 6 simple types in that list. This can be accomplished with code like the following:

当我必须实现一般的深度复制时,我最终会做出让步,假设我只需要复制一个简单的对象、数组、日期、字符串、数字或布尔值。最后三种类型是不可变的,所以我可以执行一个浅拷贝,而不用担心它会发生变化。我进一步假设对象或数组中包含的任何元素也将是该列表中的6个简单类型之一。这可以通过如下代码实现:

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

The above function will work adequately for the 6 simple types I mentioned, as long as the data in the objects and arrays form a tree structure. That is, there isn't more than one reference to the same data in the object. For example:

上面的函数将为我提到的6个简单类型充分发挥作用,只要对象和数组中的数据形成树状结构。也就是说,在对象中没有多于一个引用相同的数据。例如:

// This would be cloneable:
var tree = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "right" : null,
    "data"  : 8
};

// This would kind-of work, but you would get 2 copies of the 
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cyclicGraph["right"] = cyclicGraph;

It will not be able to handle any JavaScript object, but it may be sufficient for many purposes as long as you don't assume that it will just work for anything you throw at it.

它将不能处理任何JavaScript对象,但它可能足以满足许多目的,只要您不认为它只适用于您抛出的任何东西。

#2


705  

With jQuery, you can shallow copy with extend:

使用jQuery,您可以使用扩展:

var copiedObject = jQuery.extend({}, originalObject)

subsequent changes to the copiedObject will not affect the originalObject, and vice versa.

对copiedObject的后续更改不会影响原始对象,反之亦然。

Or to make a deep copy:

或者做一个深入的复制:

var copiedObject = jQuery.extend(true, {}, originalObject)

#3


664  

If you do not use functions within your object, a very simple one liner can be the following:

如果您不使用对象中的函数,那么非常简单的一行可以是:

var cloneOfA = JSON.parse(JSON.stringify(a));

This works for all kind of objects containing objects, arrays, strings, booleans and numbers.

这适用于所有类型的对象,包括对象、数组、字符串、布尔值和数字。

See also this article about the structured clone algorithm of browsers which is used when posting messages to and from a worker. It also contains a function for deep cloning.

本文还介绍了在向工作人员发送消息时使用的浏览器的结构化克隆算法。它还包含了深度克隆的功能。

#4


432  

In ECMAScript 6 there is Object.assign method, which copies values of all enumerable own properties from one object to another. For example:

在ECMAScript 6中有一个对象。分配方法,该方法将所有可枚举的自身属性的值从一个对象复制到另一个对象。例如:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

But be aware that nested objects are still copied as reference.

但是请注意,仍然将嵌套的对象作为引用复制。

#5


111  

There are many answers, but none that mentions Object.create from ECMAScript 5, which admittedly does not give you an exact copy, but sets the source as the prototype of the new object.

有很多答案,但没有一个提到对象。从ECMAScript 5创建,它确实没有给您一个确切的副本,但是将源设置为新对象的原型。

Thus, this is not an exact answer to the question, but it is a one-line solution and thus elegant. And it works best for 2 cases:

因此,这不是问题的确切答案,但它是一个单线解决方案,因此是优雅的。它适用于两种情况:

  1. Where such inheritance is useful (duh!)
  2. 这样的遗传是有用的(duh!)
  3. Where the source object won't be modified, thus making the relation between the 2 objects a non issue.
  4. 如果源对象不被修改,则将两个对象之间的关系变为非问题。

Example:

例子:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

Why do I consider this solution to be superior? It's native, thus no looping, no recursion. However, older browsers will need a polyfill.

为什么我认为这个解决方案更优越?它是本地的,因此没有循环,没有递归。但是,旧的浏览器需要一个polyfill。

#6


102  

An elegant way to clone a Javascript object in one line of code

An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need.

一个对象。分配方法是ECMAScript 2015 (ES6)标准的一部分,它完全符合您的需要。

var clone = Object.assign({}, obj);

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.

object. assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。

Read more...

阅读更多…

The polyfill to support older browsers:

支持旧浏览器的polyfill:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

#7


91  

Per MDN:

每中数:

  • If you want shallow copy, use Object.assign({}, a)
  • 如果你想要浅拷贝,可以使用对象。分配({ })
  • For "deep" copy, use JSON.parse(JSON.stringify(a))
  • 对于“深度”复制,使用JSON.parse(JSON.stringify(a))

There is no need for external libraries but you need to check browser compatibility first.

不需要外部库,但首先需要检查浏览器兼容性。

#8


68  

If you're okay with a shallow copy, the underscore.js library has a clone method.

如果你可以用浅拷贝,下划线。js库有一个克隆方法。

y = _.clone(x);

or you can extend it like

或者你可以扩展它。

copiedObject = _.extend({},originalObject);

#9


61  

There are several issues with most solutions on the internet. So I decided to make a follow-up, which includes, why the accepted answer shouldn't be accepted.

互联网上的大多数解决方案都有几个问题。所以我决定做一个后续的,包括,为什么接受的答案不应该被接受。

starting situation

I want to deep-copy a Javascript Object with all of its children and their children and so on. But since I'm not kind of a normal developer, my Object has normal properties, circular structures and even nested objects.

我想要将一个Javascript对象和它的所有子对象以及它们的子对象进行深度复制。但由于我不是一般的开发人员,所以我的对象具有正常的属性、圆形结构甚至嵌套对象。

So let's create a circular structure and a nested object first.

我们先创建一个圆形结构和一个嵌套对象。

function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}

Let's bring everything together in an Object named a.

让我们把所有的东西都放到一个名为a的对象中。

var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};

Next, we want to copy a into a variable named b and mutate it.

接下来,我们要将a复制到一个名为b的变量中,并将其进行变异。

var b = a;

b.x = 'b';
b.nested.y = 'b';

You know what happened here because if not you wouldn't even land on this great question.

你知道这里发生了什么,因为如果你不愿意,你甚至都不会在这个伟大的问题上降落。

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

Now let's find a solution.

现在让我们找到一个解。

JSON

The first attempt I tried was using JSON.

我尝试的第一个尝试是使用JSON。

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

Don't waste too much time on it, you'll get TypeError: Converting circular structure to JSON.

不要在它上面浪费太多时间,您会得到类型错误:将圆形结构转换为JSON。

Recursive copy (the accepted "answer")

Let's have a look at the accepted answer.

让我们看一下公认的答案。

function cloneSO(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Looks good, heh? It's a recursive copy of the object and handles other types as well, like Date, but that wasn't a requirement.

看起来不错,哈?它是对象的递归副本,并处理其他类型,比如日期,但这不是必需的。

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

Recursion and circular structures doesn't work well together... RangeError: Maximum call stack size exceeded

递归和循环结构不能很好地结合在一起…RangeError:超过了最大调用堆栈大小。

native solution

After arguing with my co-worker, my boss asked us what happened, and he found a simple solution after some googling. It's called Object.create.

在和同事吵了一架之后,老板问我们发生了什么事,他在谷歌搜索后找到了一个简单的解决方案。它叫做Object.create。

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';

This solution was added to Javascript some time ago and even handles circular structure.

这个解决方案在一段时间以前被添加到Javascript中,甚至可以处理循环结构。

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

... and you see, it didn't work with the nested structure inside.

…你看,它并没有使用嵌套的结构。

polyfill for the native solution

There's a polyfill for Object.create in the older browser just like the IE 8. It's something like recommended by Mozilla, and of course, it's not perfect and results in the same problem as the native solution.

对象有一个polyfill。在旧浏览器中创建,就像IE 8一样。这是Mozilla推荐的,当然,它并不完美,结果与本地解决方案相同。

function F() {};
function clonePF(o) {
    F.prototype = o;
    return new F();
}

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';

I've put F outside the scope so we can have a look at what instanceof tells us.

我已经把F放到了范围之外,这样我们就可以看一下instanceof告诉我们什么了。

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

Same problem as the native solution, but a little bit worse output.

与本机解决方案相同,但输出更糟。

the better (but not perfect) solution

When digging around, I found a similar question (In Javascript, when performing a deep copy, how do I avoid a cycle, due to a property being "this"?) to this one, but with a way better solution.

在挖掘时,我发现了一个类似的问题(在Javascript中,当执行深度复制时,如何避免一个循环,因为一个属性是“this”?),但有一个更好的解决方案。

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; // primitive value
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

And let's have a look at the output...

让我们看一下输出…

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

The requirements are matched, but there are still some smaller issues, including changing the instance of nested and circ to Object.

需求是匹配的,但是仍然存在一些较小的问题,包括将嵌套和circ的实例更改为对象。

The structure of trees that share a leaf won't be copied, they will become two independent leaves:

树叶的结构不会被复制,它们会变成两个独立的叶子:

        [Object]                     [Object]
         /    \                       /    \
        /      \                     /      \
      |/_      _\|                 |/_      _\|  
  [Object]    [Object]   ===>  [Object]    [Object]
       \        /                 |           |
        \      /                  |           |
        _\|  |/_                 \|/         \|/
        [Object]               [Object]    [Object]

conclusion

The last solution using recursion and a cache, may not be the best, but it's a real deep-copy of the object. It handles simple properties, circular structures and nested object, but it will mess up the instance of them while cloning.

使用递归和缓存的最后一个解决方案可能不是最好的,但它是对象的一个真正的深层副本。它处理简单的属性、圆形结构和嵌套对象,但是在克隆时它会破坏它们的实例。

http://jsfiddle.net/einfallstoll/N4mr2/

http://jsfiddle.net/einfallstoll/N4mr2/

#10


34  

One particularly inelegant solution is to use JSON encoding to make deep copies of objects that do not have member methods. The methodology is to JSON encode your target object, then by decoding it, you get the copy you are looking for. You can decode as many times as you want to make as many copies as you need.

一个特别不优雅的解决方案是使用JSON编码来复制没有成员方法的对象的深层副本。方法是JSON编码你的目标对象,然后通过解码,你得到你要找的副本。你可以解码多少次,你想要多少复制你需要。

Of course, functions do not belong in JSON, so this only works for objects without member methods.

当然,函数不属于JSON,所以这只适用于没有成员方法的对象。

This methodology was perfect for my use case, since I'm storing JSON blobs in a key-value store, and when they are exposed as objects in a JavaScript API, each object actually contains a copy of the original state of the object so we can calculate the delta after the caller has mutated the exposed object.

这方法适合我的用例,因为我将JSON blob存储在一个键值存储,当他们在一个JavaScript API公开为对象,每个对象实际上包含了原始状态的对象的一个副本后我们可以计算出三角洲调用者暴露对象产生了变异。

var object1 = {key:"value"};
var object2 = object1;

object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);

object2.key = "a change";
console.log(object1);// returns value

#11


23  

For those using AngularJS, there is also direct method for cloning or extending of the objects in this library.

对于那些使用AngularJS的人,在这个库中也有克隆或扩展对象的直接方法。

var destination = angular.copy(source);

or

angular.copy(source, destination);

More in angular.copy documentation...

角。复制文档…

#12


20  

You can simply use a spread property to copy an object without references. But be careful (see comments), the 'copy' is just on the lowest object/array level. Nested properties are still references!

您可以简单地使用一个扩展属性来复制一个没有引用的对象。但是要小心(参见注释),“copy”只是在最低的对象/数组级别上。嵌套属性仍然是引用!


Complete clone:

完整的克隆:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

Clone with references on second level:

在第二级引用的克隆:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

JavaScript actually does not support deep clones natively. Use an utility function. For example Ramda:

JavaScript实际上不支持深层克隆。使用一个效用函数。例如Ramda:

http://ramdajs.com/docs/#clone

http://ramdajs.com/docs/克隆

#13


20  

OK, imagine you have this object below and you want to clone it:

假设你有下面这个物体,你想克隆它:

let obj = {a:1, b:2, c:3}; //ES6

or

var obj = {a:1, b:2, c:3}; //ES5

The answer is mainly depeneds on which ECMAscript you using, in ES6+, you can simply use Object.assign to do the clone:

答案主要取决于您使用的ECMAscript,在ES6+中,您可以简单地使用对象。指定克隆:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

or using spread operator like this:

或者使用像这样的传播算子:

let cloned = {...obj}; //new {a:1, b:2, c:3};

But if you using ES5, you can use few methods, but the JSON.stringify, just make sure you not using for a big chunk of data to copy, but it could be one line handy way in many cases, something like this:

但是如果使用ES5,您可以使用很少的方法,但是JSON。stringify,只是确保你没有使用大量的数据来复制,但是在很多情况下,它可以是一个很方便的方法,比如:

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

#14


19  

A.Levy's answer is almost complete, here is my little contribution: there is a way how to handle recursive references, see this line

一个。Levy的回答几乎是完整的,这是我的小小贡献:有一种方法可以处理递归引用,请参阅这一行。

if(this[attr]==this) copy[attr] = copy;

如果(这attr = =)[attr]=副本复印件;

If the object is XML DOM element, we must use cloneNode instead

如果对象是XML DOM元素,则必须使用cloneNode。

if(this.cloneNode) return this.cloneNode(true);

如果(this.cloneNode)返回this.cloneNode(真正的);

Inspired by A.Levy's exhaustive study and Calvin's prototyping approach, I offer this solution:

灵感来自一个。Levy的详尽研究和卡尔文的原型方法,我提供了这个解决方案:

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

See also Andy Burke's note in the answers.

看看安迪·伯克的答案。

#15


18  

From this article: How to copy arrays and objects in Javascript by Brian Huisman:

从这篇文章中:Brian Huisman如何在Javascript中复制数组和对象:

Object.prototype.clone = function() {
  var newObj = (this instanceof Array) ? [] : {};
  for (var i in this) {
    if (i == 'clone') continue;
    if (this[i] && typeof this[i] == "object") {
      newObj[i] = this[i].clone();
    } else newObj[i] = this[i]
  } return newObj;
};

#16


18  

In ES-6 you can simply use Object.assign(...). Ex:

在-6中,你可以简单地使用Object.assign(…)。例:

let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);

A good reference is here: https://googlechrome.github.io/samples/object-assign-es6/

这里有一个很好的参考:https://googlechrome.github.io/samples/object- -es6/。

#17


16  

Here is a function you can use.

这是一个您可以使用的函数。

function clone(obj) {
    if(obj == null || typeof(obj) != 'object')
        return obj;    
    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);    
    return temp;
}

#18


14  

You can clone an object and remove any reference from the previous one using a single line of code. Simply do:

您可以克隆一个对象,并使用一行代码删除前一个对象的任何引用。只是做的事:

var obj1 = { text: 'moo1' };
var obj2 = Object.create(obj1); // Creates a new clone without references

obj2.text = 'moo2'; // Only updates obj2's text property

console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'}

For browsers / engines that do not currently support Object.create you can use this polyfill:

对于当前不支持对象的浏览器/引擎。创建你可以使用这个polyfill:

// Polyfill Object.create if it does not exist
if (!Object.create) {
    Object.create = function (o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    };
}

#19


11  

New answer to an old question! If you have the pleasure of having using ECMAScript 2016 (ES6) with Spread Syntax, it's easy.

一个老问题的新答案!如果您有幸使用ECMAScript 2016 (ES6)和扩展语法,这很容易。

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

This provides a clean method for a shallow copy of an object. Making a deep copy, meaning makign a new copy of every value in every recursively nested object, requires on of the heavier solutions above.

这为对象的浅拷贝提供了一种干净的方法。制作一个深度拷贝,意味着在每个递归嵌套的对象中创建每个值的新副本,这需要上面的更重的解决方案。

JavaScript keeps evolving.

JavaScript不断演变。

#20


10  

Using Lodash:

使用Lodash:

var y = _.clone(x, true);

#21


8  

Interested in cloning simple objects :

对克隆简单对象感兴趣:

JSON.parse(JSON.stringify(json_original));

JSON.parse(JSON.stringify(json_original));

Source : How to copy JavaScript object to new variable NOT by reference?

源:如何将JavaScript对象复制到新变量而不是引用?

#22


8  

let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

ES6 solution if you want to (shallow) clone a class instance and not just a property object.

如果您想(浅)克隆一个类实例,而不只是一个属性对象,那么可以使用ES6解决方案。

#23


6  

Jan Turoň's answer above is very close, and may be the best to use in a browser due to compatibility issues, but it will potentially cause some strange enumeration issues. For instance, executing:

Jan Turoň上面的回答是非常接近,可能是最好的在浏览器中使用由于兼容性问题,但它可能会导致一些奇怪的枚举问题。例如,执行:

for ( var i in someArray ) { ... }

Will assign the clone() method to i after iterating through the elements of the array. Here's an adaptation that avoids the enumeration and works with node.js:

将在遍历数组元素之后将clone()方法分配给i。以下是一种避免列举和使用node.js的适应方法:

Object.defineProperty( Object.prototype, "clone", {
    value: function() {
        if ( this.cloneNode )
        {
            return this.cloneNode( true );
        }

        var copy = this instanceof Array ? [] : {};
        for( var attr in this )
        {
            if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone )
            {
                copy[ attr ] = this[ attr ];
            }
            else if ( this[ attr ] == this )
            {
                copy[ attr ] = copy;
            }
            else
            {
                copy[ attr ] = this[ attr ].clone();
            }
        }
        return copy;
    }
});

Object.defineProperty( Date.prototype, "clone", {
    value: function() {
        var copy = new Date();
        copy.setTime( this.getTime() );
        return copy;
    }
});

Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );

This avoids making the clone() method enumerable because defineProperty() defaults enumerable to false.

这避免了克隆()方法的可枚举性,因为定义属性()默认值为false。

#24


6  

This is an adaptation of A. Levy's code to also handle the cloning of functions and multiple/cyclic references - what this means is that if two properties in the tree which is cloned are references of the same object, the cloned object tree will have these properties point to one and the same clone of the referenced object. This also solves the case of cyclic dependencies which, if left unhandled, leads to an infinite loop. The complexity of the algorithm is O(n)

这是一个改编的a·利维的代码也处理函数和多个/循环引用的克隆——这意味着,如果两个属性树中的克隆是相同的对象的引用,克隆的对象树将这些属性指向同一个引用对象的克隆。这也解决了循环依赖的情况,如果不处理,会导致无限循环。算法复杂度为O(n)

function clone(obj){
    var clonedObjectsArray = [];
    var originalObjectsArray = []; //used to remove the unique ids when finished
    var next_objid = 0;

    function objectId(obj) {
        if (obj == null) return null;
        if (obj.__obj_id == undefined){
            obj.__obj_id = next_objid++;
            originalObjectsArray[obj.__obj_id] = obj;
        }
        return obj.__obj_id;
    }

    function cloneRecursive(obj) {
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;

        // Handle Date
        if (obj instanceof Date) {
            var copy = new Date();
            copy.setTime(obj.getTime());
            return copy;
        }

        // Handle Array
        if (obj instanceof Array) {
            var copy = [];
            for (var i = 0; i < obj.length; ++i) {
                copy[i] = cloneRecursive(obj[i]);
            }
            return copy;
        }

        // Handle Object
        if (obj instanceof Object) {
            if (clonedObjectsArray[objectId(obj)] != undefined)
                return clonedObjectsArray[objectId(obj)];

            var copy;
            if (obj instanceof Function)//Handle Function
                copy = function(){return obj.apply(this, arguments);};
            else
                copy = {};

            clonedObjectsArray[objectId(obj)] = copy;

            for (var attr in obj)
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))
                    copy[attr] = cloneRecursive(obj[attr]);                 

            return copy;
        }       


        throw new Error("Unable to copy obj! Its type isn't supported.");
    }
    var cloneObj = cloneRecursive(obj);



    //remove the unique ids
    for (var i = 0; i < originalObjectsArray.length; i++)
    {
        delete originalObjectsArray[i].__obj_id;
    };

    return cloneObj;
}

Some quick tests

一些快速测试

var auxobj = {
    prop1 : "prop1 aux val", 
    prop2 : ["prop2 item1", "prop2 item2"]
    };

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
    this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));

#25


5  

I just wanted to add to all the Object.create solutions in this post, that this does not work in the desired way with nodejs.

我只是想把所有的东西都加进去。在本文中创建解决方案,这与nodejs所期望的方法不一样。

In Firefox the result of

在Firefox中。

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

is

{test:"test"}.

{测试:“测试”}。

In nodejs it is

在nodejs

{}

#26


5  

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if(!src && typeof src != "object"){
        //any non-object ( Boolean, String, Number ), null, undefined, NaN
        return src;
    }

    //Honor native/custom clone methods
    if(src.clone && toString.call(src.clone) == "[object Function]"){
        return src.clone(deep);
    }

    //DOM Elements
    if(src.nodeType && toString.call(src.cloneNode) == "[object Function]"){
        return src.cloneNode(deep);
    }

    //Date
    if(toString.call(src) == "[object Date]"){
        return new Date(src.getTime());
    }

    //RegExp
    if(toString.call(src) == "[object RegExp]"){
        return new RegExp(src);
    }

    //Function
    if(toString.call(src) == "[object Function]"){
        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });

    }

    var ret, index;
    //Array
    if(toString.call(src) == "[object Array]"){
        //[].slice(0) would soft clone
        ret = src.slice();
        if(deep){
            index = ret.length;
            while(index--){
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }

    return ret;
};

#27


5  

Since mindeavor stated that the object to be cloned is a 'literal-constructed' object, a solution might be to simply generate the object multiple times rather than cloning an instance of the object:

由于mindeavor声明要克隆的对象是一个“文本构建”对象,一个解决方案可能是简单地生成对象,而不是克隆对象的实例:

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

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

#28


5  

I've written my own implementation. Not sure if it counts as a better solution:

我已经编写了自己的实现。不确定这是否是一个更好的解决方案:

/*
    a function for deep cloning objects that contains other nested objects and circular structures.
    objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
                                    index (z)
                                         |
                                         |
                                         |
                                         |
                                         |
                                         |                      depth (x)
                                         |_ _ _ _ _ _ _ _ _ _ _ _
                                        /_/_/_/_/_/_/_/_/_/
                                       /_/_/_/_/_/_/_/_/_/
                                      /_/_/_/_/_/_/...../
                                     /................./
                                    /.....            /
                                   /                 /
                                  /------------------
            object length (y)    /
*/

Following is the implementation:

下面是实现:

function deepClone(obj) {
    var depth = -1;
    var arr = [];
    return clone(obj, arr, depth);
}

/**
 *
 * @param obj source object
 * @param arr 3D array to store the references to objects
 * @param depth depth of the current object relative to the passed 'obj'
 * @returns {*}
 */
function clone(obj, arr, depth){
    if (typeof obj !== "object") {
        return obj;
    }

    var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'

    var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
    if(result instanceof Array){
        result.length = length;
    }

    depth++; // depth is increased because we entered an object here

    arr[depth] = []; // this is the x-axis, each index here is the depth
    arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
    // start the depth at current and go down, cyclic structures won't form on depths more than the current one
    for(var x = depth; x >= 0; x--){
        // loop only if the array at this depth and length already have elements
        if(arr[x][length]){
            for(var index = 0; index < arr[x][length].length; index++){
                if(obj === arr[x][length][index]){
                    return obj;
                }
            }
        }
    }

    arr[depth][length].push(obj); // store the object in the array at the current depth and length
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
    }

    return result;
}

#29


5  

Bellow is my version of deep cloning, covering functions and with handling for circular references.

Bellow是我的深度克隆版,覆盖功能和处理循环引用。

https://github.com/radsimu/UaicNlpToolkit/blob/master/Modules/GGS/GGSEngine/src/main/resources/ro/uaic/info/nlptools/ggs/engine/core/jsInitCode.js#L17

https://github.com/radsimu/UaicNlpToolkit/blob/master/Modules/GGS/GGSEngine/src/main/resources/ro/uaic/info/nlptools/ggs/engine/core/jsInitCode.js L17

#30


4  

Consult http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data for the W3C's "Safe passing of structured data" algorithm, intended to be implemented by browsers for passing data to eg web workers. However, it has some limitations, in that it does not handle functions. See https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm for more information, including an alternative algorithm in JS which gets you part of the way there.

请参考http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#为W3C“安全传递结构化数据”算法提供的结构化数据,旨在通过浏览器实现将数据传递给web workers。但是,它有一些限制,因为它不处理函数。请参阅https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm以获取更多信息,包括在JS中使用的另一种算法,它可以让您了解其中的一部分。

#1


1235  

Updated answer

Just use Object.assign() as suggested here

只要使用Object.assign()就像这里建议的那样。


Outdated answer

To do this for any object in JavaScript will not be simple or straightforward. You will run into the problem of erroneously picking up attributes from the object's prototype that should be left in the prototype and not copied to the new instance. If, for instance, you are adding a clone method to Object.prototype, as some answers depict, you will need to explicitly skip that attribute. But what if there are other additional methods added to Object.prototype, or other intermediate prototypes, that you don't know about? In that case, you will copy attributes you shouldn't, so you need to detect unforeseen, non-local attributes with the hasOwnProperty method.

对于JavaScript中的任何对象,这样做都不是简单或直接的。您将遇到错误地从对象的原型中获取属性的问题,这些属性应该留在原型中,而不是复制到新实例中。例如,如果您正在为对象添加克隆方法。原型,正如一些回答所描述的那样,您需要显式地跳过该属性。但是如果有其他附加的方法添加到对象中会怎么样呢?原型,或者其他的中间原型,你不知道?在这种情况下,您将复制不应该复制的属性,因此您需要使用hasOwnProperty方法检测未预见的非本地属性。

In addition to non-enumerable attributes, you'll encounter a tougher problem when you try to copy objects that have hidden properties. For example, prototype is a hidden property of a function. Also, an object's prototype is referenced with the attribute __proto__, which is also hidden, and will not be copied by a for/in loop iterating over the source object's attributes. I think __proto__ might be specific to Firefox's JavaScript interpreter and it may be something different in other browsers, but you get the picture. Not everything is enumerable. You can copy a hidden attribute if you know its name, but I don't know of any way to discover it automatically.

除了不可枚举的属性之外,当您试图复制具有隐藏属性的对象时,您会遇到更棘手的问题。例如,prototype是函数的一个隐藏属性。另外,一个对象的原型与属性__proto__一起被引用,它也是隐藏的,并且不会被一个for/in循环复制到源对象的属性中。我认为__proto__可能是Firefox的JavaScript解释器所特有的,它可能在其他浏览器中有所不同,但是你可以看到它。并不是所有的。如果你知道它的名字,你可以复制一个隐藏的属性,但是我不知道有什么方法可以自动发现它。

Yet another snag in the quest for an elegant solution is the problem of setting up the prototype inheritance correctly. If your source object's prototype is Object, then simply creating a new general object with {} will work, but if the source's prototype is some descendant of Object, then you are going to be missing the additional members from that prototype which you skipped using the hasOwnProperty filter, or which were in the prototype, but weren't enumerable in the first place. One solution might be to call the source object's constructor property to get the initial copy object and then copy over the attributes, but then you still will not get non-enumerable attributes. For example, a Date object stores its data as a hidden member:

另一个追求优雅解决方案的障碍是正确设置原型继承的问题。如果你的源对象的原型对象,然后简单地创建一个新的通用对象用{ }将工作,但如果源的原型对象的一些后代,那么你将要错过了其他成员的原型,你跳过使用hasOwnProperty过滤器,或在原型,但没有可在第一时间。一个解决方案可能是调用源对象的构造函数来获取初始的复制对象,然后复制这些属性,但是您仍然不会得到不可枚举的属性。例如,Date对象将其数据存储为隐藏成员:

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
    var d2 = clone(d1);
    alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
}, 5000);

The date string for d1 will be 5 seconds behind that of d2. A way to make one Date the same as another is by calling the setTime method, but that is specific to the Date class. I don't think there is a bullet-proof general solution to this problem, though I would be happy to be wrong!

d1的日期字符串将比d2晚5秒。使一个日期与另一个日期相同的方法是调用setTime方法,但这是特定于日期类的。我不认为这个问题有一个防弹一般的解决方案,尽管我很高兴错了!

When I had to implement general deep copying I ended up compromising by assuming that I would only need to copy a plain Object, Array, Date, String, Number, or Boolean. The last 3 types are immutable, so I could perform a shallow copy and not worry about it changing. I further assumed that any elements contained in Object or Array would also be one of the 6 simple types in that list. This can be accomplished with code like the following:

当我必须实现一般的深度复制时,我最终会做出让步,假设我只需要复制一个简单的对象、数组、日期、字符串、数字或布尔值。最后三种类型是不可变的,所以我可以执行一个浅拷贝,而不用担心它会发生变化。我进一步假设对象或数组中包含的任何元素也将是该列表中的6个简单类型之一。这可以通过如下代码实现:

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

The above function will work adequately for the 6 simple types I mentioned, as long as the data in the objects and arrays form a tree structure. That is, there isn't more than one reference to the same data in the object. For example:

上面的函数将为我提到的6个简单类型充分发挥作用,只要对象和数组中的数据形成树状结构。也就是说,在对象中没有多于一个引用相同的数据。例如:

// This would be cloneable:
var tree = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "right" : null,
    "data"  : 8
};

// This would kind-of work, but you would get 2 copies of the 
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cyclicGraph["right"] = cyclicGraph;

It will not be able to handle any JavaScript object, but it may be sufficient for many purposes as long as you don't assume that it will just work for anything you throw at it.

它将不能处理任何JavaScript对象,但它可能足以满足许多目的,只要您不认为它只适用于您抛出的任何东西。

#2


705  

With jQuery, you can shallow copy with extend:

使用jQuery,您可以使用扩展:

var copiedObject = jQuery.extend({}, originalObject)

subsequent changes to the copiedObject will not affect the originalObject, and vice versa.

对copiedObject的后续更改不会影响原始对象,反之亦然。

Or to make a deep copy:

或者做一个深入的复制:

var copiedObject = jQuery.extend(true, {}, originalObject)

#3


664  

If you do not use functions within your object, a very simple one liner can be the following:

如果您不使用对象中的函数,那么非常简单的一行可以是:

var cloneOfA = JSON.parse(JSON.stringify(a));

This works for all kind of objects containing objects, arrays, strings, booleans and numbers.

这适用于所有类型的对象,包括对象、数组、字符串、布尔值和数字。

See also this article about the structured clone algorithm of browsers which is used when posting messages to and from a worker. It also contains a function for deep cloning.

本文还介绍了在向工作人员发送消息时使用的浏览器的结构化克隆算法。它还包含了深度克隆的功能。

#4


432  

In ECMAScript 6 there is Object.assign method, which copies values of all enumerable own properties from one object to another. For example:

在ECMAScript 6中有一个对象。分配方法,该方法将所有可枚举的自身属性的值从一个对象复制到另一个对象。例如:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

But be aware that nested objects are still copied as reference.

但是请注意,仍然将嵌套的对象作为引用复制。

#5


111  

There are many answers, but none that mentions Object.create from ECMAScript 5, which admittedly does not give you an exact copy, but sets the source as the prototype of the new object.

有很多答案,但没有一个提到对象。从ECMAScript 5创建,它确实没有给您一个确切的副本,但是将源设置为新对象的原型。

Thus, this is not an exact answer to the question, but it is a one-line solution and thus elegant. And it works best for 2 cases:

因此,这不是问题的确切答案,但它是一个单线解决方案,因此是优雅的。它适用于两种情况:

  1. Where such inheritance is useful (duh!)
  2. 这样的遗传是有用的(duh!)
  3. Where the source object won't be modified, thus making the relation between the 2 objects a non issue.
  4. 如果源对象不被修改,则将两个对象之间的关系变为非问题。

Example:

例子:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

Why do I consider this solution to be superior? It's native, thus no looping, no recursion. However, older browsers will need a polyfill.

为什么我认为这个解决方案更优越?它是本地的,因此没有循环,没有递归。但是,旧的浏览器需要一个polyfill。

#6


102  

An elegant way to clone a Javascript object in one line of code

An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need.

一个对象。分配方法是ECMAScript 2015 (ES6)标准的一部分,它完全符合您的需要。

var clone = Object.assign({}, obj);

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.

object. assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。

Read more...

阅读更多…

The polyfill to support older browsers:

支持旧浏览器的polyfill:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

#7


91  

Per MDN:

每中数:

  • If you want shallow copy, use Object.assign({}, a)
  • 如果你想要浅拷贝,可以使用对象。分配({ })
  • For "deep" copy, use JSON.parse(JSON.stringify(a))
  • 对于“深度”复制,使用JSON.parse(JSON.stringify(a))

There is no need for external libraries but you need to check browser compatibility first.

不需要外部库,但首先需要检查浏览器兼容性。

#8


68  

If you're okay with a shallow copy, the underscore.js library has a clone method.

如果你可以用浅拷贝,下划线。js库有一个克隆方法。

y = _.clone(x);

or you can extend it like

或者你可以扩展它。

copiedObject = _.extend({},originalObject);

#9


61  

There are several issues with most solutions on the internet. So I decided to make a follow-up, which includes, why the accepted answer shouldn't be accepted.

互联网上的大多数解决方案都有几个问题。所以我决定做一个后续的,包括,为什么接受的答案不应该被接受。

starting situation

I want to deep-copy a Javascript Object with all of its children and their children and so on. But since I'm not kind of a normal developer, my Object has normal properties, circular structures and even nested objects.

我想要将一个Javascript对象和它的所有子对象以及它们的子对象进行深度复制。但由于我不是一般的开发人员,所以我的对象具有正常的属性、圆形结构甚至嵌套对象。

So let's create a circular structure and a nested object first.

我们先创建一个圆形结构和一个嵌套对象。

function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}

Let's bring everything together in an Object named a.

让我们把所有的东西都放到一个名为a的对象中。

var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};

Next, we want to copy a into a variable named b and mutate it.

接下来,我们要将a复制到一个名为b的变量中,并将其进行变异。

var b = a;

b.x = 'b';
b.nested.y = 'b';

You know what happened here because if not you wouldn't even land on this great question.

你知道这里发生了什么,因为如果你不愿意,你甚至都不会在这个伟大的问题上降落。

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

Now let's find a solution.

现在让我们找到一个解。

JSON

The first attempt I tried was using JSON.

我尝试的第一个尝试是使用JSON。

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

Don't waste too much time on it, you'll get TypeError: Converting circular structure to JSON.

不要在它上面浪费太多时间,您会得到类型错误:将圆形结构转换为JSON。

Recursive copy (the accepted "answer")

Let's have a look at the accepted answer.

让我们看一下公认的答案。

function cloneSO(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Looks good, heh? It's a recursive copy of the object and handles other types as well, like Date, but that wasn't a requirement.

看起来不错,哈?它是对象的递归副本,并处理其他类型,比如日期,但这不是必需的。

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

Recursion and circular structures doesn't work well together... RangeError: Maximum call stack size exceeded

递归和循环结构不能很好地结合在一起…RangeError:超过了最大调用堆栈大小。

native solution

After arguing with my co-worker, my boss asked us what happened, and he found a simple solution after some googling. It's called Object.create.

在和同事吵了一架之后,老板问我们发生了什么事,他在谷歌搜索后找到了一个简单的解决方案。它叫做Object.create。

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';

This solution was added to Javascript some time ago and even handles circular structure.

这个解决方案在一段时间以前被添加到Javascript中,甚至可以处理循环结构。

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

... and you see, it didn't work with the nested structure inside.

…你看,它并没有使用嵌套的结构。

polyfill for the native solution

There's a polyfill for Object.create in the older browser just like the IE 8. It's something like recommended by Mozilla, and of course, it's not perfect and results in the same problem as the native solution.

对象有一个polyfill。在旧浏览器中创建,就像IE 8一样。这是Mozilla推荐的,当然,它并不完美,结果与本地解决方案相同。

function F() {};
function clonePF(o) {
    F.prototype = o;
    return new F();
}

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';

I've put F outside the scope so we can have a look at what instanceof tells us.

我已经把F放到了范围之外,这样我们就可以看一下instanceof告诉我们什么了。

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

Same problem as the native solution, but a little bit worse output.

与本机解决方案相同,但输出更糟。

the better (but not perfect) solution

When digging around, I found a similar question (In Javascript, when performing a deep copy, how do I avoid a cycle, due to a property being "this"?) to this one, but with a way better solution.

在挖掘时,我发现了一个类似的问题(在Javascript中,当执行深度复制时,如何避免一个循环,因为一个属性是“this”?),但有一个更好的解决方案。

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; // primitive value
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

And let's have a look at the output...

让我们看一下输出…

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

The requirements are matched, but there are still some smaller issues, including changing the instance of nested and circ to Object.

需求是匹配的,但是仍然存在一些较小的问题,包括将嵌套和circ的实例更改为对象。

The structure of trees that share a leaf won't be copied, they will become two independent leaves:

树叶的结构不会被复制,它们会变成两个独立的叶子:

        [Object]                     [Object]
         /    \                       /    \
        /      \                     /      \
      |/_      _\|                 |/_      _\|  
  [Object]    [Object]   ===>  [Object]    [Object]
       \        /                 |           |
        \      /                  |           |
        _\|  |/_                 \|/         \|/
        [Object]               [Object]    [Object]

conclusion

The last solution using recursion and a cache, may not be the best, but it's a real deep-copy of the object. It handles simple properties, circular structures and nested object, but it will mess up the instance of them while cloning.

使用递归和缓存的最后一个解决方案可能不是最好的,但它是对象的一个真正的深层副本。它处理简单的属性、圆形结构和嵌套对象,但是在克隆时它会破坏它们的实例。

http://jsfiddle.net/einfallstoll/N4mr2/

http://jsfiddle.net/einfallstoll/N4mr2/

#10


34  

One particularly inelegant solution is to use JSON encoding to make deep copies of objects that do not have member methods. The methodology is to JSON encode your target object, then by decoding it, you get the copy you are looking for. You can decode as many times as you want to make as many copies as you need.

一个特别不优雅的解决方案是使用JSON编码来复制没有成员方法的对象的深层副本。方法是JSON编码你的目标对象,然后通过解码,你得到你要找的副本。你可以解码多少次,你想要多少复制你需要。

Of course, functions do not belong in JSON, so this only works for objects without member methods.

当然,函数不属于JSON,所以这只适用于没有成员方法的对象。

This methodology was perfect for my use case, since I'm storing JSON blobs in a key-value store, and when they are exposed as objects in a JavaScript API, each object actually contains a copy of the original state of the object so we can calculate the delta after the caller has mutated the exposed object.

这方法适合我的用例,因为我将JSON blob存储在一个键值存储,当他们在一个JavaScript API公开为对象,每个对象实际上包含了原始状态的对象的一个副本后我们可以计算出三角洲调用者暴露对象产生了变异。

var object1 = {key:"value"};
var object2 = object1;

object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);

object2.key = "a change";
console.log(object1);// returns value

#11


23  

For those using AngularJS, there is also direct method for cloning or extending of the objects in this library.

对于那些使用AngularJS的人,在这个库中也有克隆或扩展对象的直接方法。

var destination = angular.copy(source);

or

angular.copy(source, destination);

More in angular.copy documentation...

角。复制文档…

#12


20  

You can simply use a spread property to copy an object without references. But be careful (see comments), the 'copy' is just on the lowest object/array level. Nested properties are still references!

您可以简单地使用一个扩展属性来复制一个没有引用的对象。但是要小心(参见注释),“copy”只是在最低的对象/数组级别上。嵌套属性仍然是引用!


Complete clone:

完整的克隆:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

Clone with references on second level:

在第二级引用的克隆:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

JavaScript actually does not support deep clones natively. Use an utility function. For example Ramda:

JavaScript实际上不支持深层克隆。使用一个效用函数。例如Ramda:

http://ramdajs.com/docs/#clone

http://ramdajs.com/docs/克隆

#13


20  

OK, imagine you have this object below and you want to clone it:

假设你有下面这个物体,你想克隆它:

let obj = {a:1, b:2, c:3}; //ES6

or

var obj = {a:1, b:2, c:3}; //ES5

The answer is mainly depeneds on which ECMAscript you using, in ES6+, you can simply use Object.assign to do the clone:

答案主要取决于您使用的ECMAscript,在ES6+中,您可以简单地使用对象。指定克隆:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

or using spread operator like this:

或者使用像这样的传播算子:

let cloned = {...obj}; //new {a:1, b:2, c:3};

But if you using ES5, you can use few methods, but the JSON.stringify, just make sure you not using for a big chunk of data to copy, but it could be one line handy way in many cases, something like this:

但是如果使用ES5,您可以使用很少的方法,但是JSON。stringify,只是确保你没有使用大量的数据来复制,但是在很多情况下,它可以是一个很方便的方法,比如:

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

#14


19  

A.Levy's answer is almost complete, here is my little contribution: there is a way how to handle recursive references, see this line

一个。Levy的回答几乎是完整的,这是我的小小贡献:有一种方法可以处理递归引用,请参阅这一行。

if(this[attr]==this) copy[attr] = copy;

如果(这attr = =)[attr]=副本复印件;

If the object is XML DOM element, we must use cloneNode instead

如果对象是XML DOM元素,则必须使用cloneNode。

if(this.cloneNode) return this.cloneNode(true);

如果(this.cloneNode)返回this.cloneNode(真正的);

Inspired by A.Levy's exhaustive study and Calvin's prototyping approach, I offer this solution:

灵感来自一个。Levy的详尽研究和卡尔文的原型方法,我提供了这个解决方案:

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

See also Andy Burke's note in the answers.

看看安迪·伯克的答案。

#15


18  

From this article: How to copy arrays and objects in Javascript by Brian Huisman:

从这篇文章中:Brian Huisman如何在Javascript中复制数组和对象:

Object.prototype.clone = function() {
  var newObj = (this instanceof Array) ? [] : {};
  for (var i in this) {
    if (i == 'clone') continue;
    if (this[i] && typeof this[i] == "object") {
      newObj[i] = this[i].clone();
    } else newObj[i] = this[i]
  } return newObj;
};

#16


18  

In ES-6 you can simply use Object.assign(...). Ex:

在-6中,你可以简单地使用Object.assign(…)。例:

let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);

A good reference is here: https://googlechrome.github.io/samples/object-assign-es6/

这里有一个很好的参考:https://googlechrome.github.io/samples/object- -es6/。

#17


16  

Here is a function you can use.

这是一个您可以使用的函数。

function clone(obj) {
    if(obj == null || typeof(obj) != 'object')
        return obj;    
    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);    
    return temp;
}

#18


14  

You can clone an object and remove any reference from the previous one using a single line of code. Simply do:

您可以克隆一个对象,并使用一行代码删除前一个对象的任何引用。只是做的事:

var obj1 = { text: 'moo1' };
var obj2 = Object.create(obj1); // Creates a new clone without references

obj2.text = 'moo2'; // Only updates obj2's text property

console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'}

For browsers / engines that do not currently support Object.create you can use this polyfill:

对于当前不支持对象的浏览器/引擎。创建你可以使用这个polyfill:

// Polyfill Object.create if it does not exist
if (!Object.create) {
    Object.create = function (o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    };
}

#19


11  

New answer to an old question! If you have the pleasure of having using ECMAScript 2016 (ES6) with Spread Syntax, it's easy.

一个老问题的新答案!如果您有幸使用ECMAScript 2016 (ES6)和扩展语法,这很容易。

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

This provides a clean method for a shallow copy of an object. Making a deep copy, meaning makign a new copy of every value in every recursively nested object, requires on of the heavier solutions above.

这为对象的浅拷贝提供了一种干净的方法。制作一个深度拷贝,意味着在每个递归嵌套的对象中创建每个值的新副本,这需要上面的更重的解决方案。

JavaScript keeps evolving.

JavaScript不断演变。

#20


10  

Using Lodash:

使用Lodash:

var y = _.clone(x, true);

#21


8  

Interested in cloning simple objects :

对克隆简单对象感兴趣:

JSON.parse(JSON.stringify(json_original));

JSON.parse(JSON.stringify(json_original));

Source : How to copy JavaScript object to new variable NOT by reference?

源:如何将JavaScript对象复制到新变量而不是引用?

#22


8  

let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

ES6 solution if you want to (shallow) clone a class instance and not just a property object.

如果您想(浅)克隆一个类实例,而不只是一个属性对象,那么可以使用ES6解决方案。

#23


6  

Jan Turoň's answer above is very close, and may be the best to use in a browser due to compatibility issues, but it will potentially cause some strange enumeration issues. For instance, executing:

Jan Turoň上面的回答是非常接近,可能是最好的在浏览器中使用由于兼容性问题,但它可能会导致一些奇怪的枚举问题。例如,执行:

for ( var i in someArray ) { ... }

Will assign the clone() method to i after iterating through the elements of the array. Here's an adaptation that avoids the enumeration and works with node.js:

将在遍历数组元素之后将clone()方法分配给i。以下是一种避免列举和使用node.js的适应方法:

Object.defineProperty( Object.prototype, "clone", {
    value: function() {
        if ( this.cloneNode )
        {
            return this.cloneNode( true );
        }

        var copy = this instanceof Array ? [] : {};
        for( var attr in this )
        {
            if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone )
            {
                copy[ attr ] = this[ attr ];
            }
            else if ( this[ attr ] == this )
            {
                copy[ attr ] = copy;
            }
            else
            {
                copy[ attr ] = this[ attr ].clone();
            }
        }
        return copy;
    }
});

Object.defineProperty( Date.prototype, "clone", {
    value: function() {
        var copy = new Date();
        copy.setTime( this.getTime() );
        return copy;
    }
});

Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );

This avoids making the clone() method enumerable because defineProperty() defaults enumerable to false.

这避免了克隆()方法的可枚举性,因为定义属性()默认值为false。

#24


6  

This is an adaptation of A. Levy's code to also handle the cloning of functions and multiple/cyclic references - what this means is that if two properties in the tree which is cloned are references of the same object, the cloned object tree will have these properties point to one and the same clone of the referenced object. This also solves the case of cyclic dependencies which, if left unhandled, leads to an infinite loop. The complexity of the algorithm is O(n)

这是一个改编的a·利维的代码也处理函数和多个/循环引用的克隆——这意味着,如果两个属性树中的克隆是相同的对象的引用,克隆的对象树将这些属性指向同一个引用对象的克隆。这也解决了循环依赖的情况,如果不处理,会导致无限循环。算法复杂度为O(n)

function clone(obj){
    var clonedObjectsArray = [];
    var originalObjectsArray = []; //used to remove the unique ids when finished
    var next_objid = 0;

    function objectId(obj) {
        if (obj == null) return null;
        if (obj.__obj_id == undefined){
            obj.__obj_id = next_objid++;
            originalObjectsArray[obj.__obj_id] = obj;
        }
        return obj.__obj_id;
    }

    function cloneRecursive(obj) {
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;

        // Handle Date
        if (obj instanceof Date) {
            var copy = new Date();
            copy.setTime(obj.getTime());
            return copy;
        }

        // Handle Array
        if (obj instanceof Array) {
            var copy = [];
            for (var i = 0; i < obj.length; ++i) {
                copy[i] = cloneRecursive(obj[i]);
            }
            return copy;
        }

        // Handle Object
        if (obj instanceof Object) {
            if (clonedObjectsArray[objectId(obj)] != undefined)
                return clonedObjectsArray[objectId(obj)];

            var copy;
            if (obj instanceof Function)//Handle Function
                copy = function(){return obj.apply(this, arguments);};
            else
                copy = {};

            clonedObjectsArray[objectId(obj)] = copy;

            for (var attr in obj)
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))
                    copy[attr] = cloneRecursive(obj[attr]);                 

            return copy;
        }       


        throw new Error("Unable to copy obj! Its type isn't supported.");
    }
    var cloneObj = cloneRecursive(obj);



    //remove the unique ids
    for (var i = 0; i < originalObjectsArray.length; i++)
    {
        delete originalObjectsArray[i].__obj_id;
    };

    return cloneObj;
}

Some quick tests

一些快速测试

var auxobj = {
    prop1 : "prop1 aux val", 
    prop2 : ["prop2 item1", "prop2 item2"]
    };

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
    this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));

#25


5  

I just wanted to add to all the Object.create solutions in this post, that this does not work in the desired way with nodejs.

我只是想把所有的东西都加进去。在本文中创建解决方案,这与nodejs所期望的方法不一样。

In Firefox the result of

在Firefox中。

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

is

{test:"test"}.

{测试:“测试”}。

In nodejs it is

在nodejs

{}

#26


5  

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if(!src && typeof src != "object"){
        //any non-object ( Boolean, String, Number ), null, undefined, NaN
        return src;
    }

    //Honor native/custom clone methods
    if(src.clone && toString.call(src.clone) == "[object Function]"){
        return src.clone(deep);
    }

    //DOM Elements
    if(src.nodeType && toString.call(src.cloneNode) == "[object Function]"){
        return src.cloneNode(deep);
    }

    //Date
    if(toString.call(src) == "[object Date]"){
        return new Date(src.getTime());
    }

    //RegExp
    if(toString.call(src) == "[object RegExp]"){
        return new RegExp(src);
    }

    //Function
    if(toString.call(src) == "[object Function]"){
        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });

    }

    var ret, index;
    //Array
    if(toString.call(src) == "[object Array]"){
        //[].slice(0) would soft clone
        ret = src.slice();
        if(deep){
            index = ret.length;
            while(index--){
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }

    return ret;
};

#27


5  

Since mindeavor stated that the object to be cloned is a 'literal-constructed' object, a solution might be to simply generate the object multiple times rather than cloning an instance of the object:

由于mindeavor声明要克隆的对象是一个“文本构建”对象,一个解决方案可能是简单地生成对象,而不是克隆对象的实例:

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

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

#28


5  

I've written my own implementation. Not sure if it counts as a better solution:

我已经编写了自己的实现。不确定这是否是一个更好的解决方案:

/*
    a function for deep cloning objects that contains other nested objects and circular structures.
    objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
                                    index (z)
                                         |
                                         |
                                         |
                                         |
                                         |
                                         |                      depth (x)
                                         |_ _ _ _ _ _ _ _ _ _ _ _
                                        /_/_/_/_/_/_/_/_/_/
                                       /_/_/_/_/_/_/_/_/_/
                                      /_/_/_/_/_/_/...../
                                     /................./
                                    /.....            /
                                   /                 /
                                  /------------------
            object length (y)    /
*/

Following is the implementation:

下面是实现:

function deepClone(obj) {
    var depth = -1;
    var arr = [];
    return clone(obj, arr, depth);
}

/**
 *
 * @param obj source object
 * @param arr 3D array to store the references to objects
 * @param depth depth of the current object relative to the passed 'obj'
 * @returns {*}
 */
function clone(obj, arr, depth){
    if (typeof obj !== "object") {
        return obj;
    }

    var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'

    var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
    if(result instanceof Array){
        result.length = length;
    }

    depth++; // depth is increased because we entered an object here

    arr[depth] = []; // this is the x-axis, each index here is the depth
    arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
    // start the depth at current and go down, cyclic structures won't form on depths more than the current one
    for(var x = depth; x >= 0; x--){
        // loop only if the array at this depth and length already have elements
        if(arr[x][length]){
            for(var index = 0; index < arr[x][length].length; index++){
                if(obj === arr[x][length][index]){
                    return obj;
                }
            }
        }
    }

    arr[depth][length].push(obj); // store the object in the array at the current depth and length
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
    }

    return result;
}

#29


5  

Bellow is my version of deep cloning, covering functions and with handling for circular references.

Bellow是我的深度克隆版,覆盖功能和处理循环引用。

https://github.com/radsimu/UaicNlpToolkit/blob/master/Modules/GGS/GGSEngine/src/main/resources/ro/uaic/info/nlptools/ggs/engine/core/jsInitCode.js#L17

https://github.com/radsimu/UaicNlpToolkit/blob/master/Modules/GGS/GGSEngine/src/main/resources/ro/uaic/info/nlptools/ggs/engine/core/jsInitCode.js L17

#30


4  

Consult http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data for the W3C's "Safe passing of structured data" algorithm, intended to be implemented by browsers for passing data to eg web workers. However, it has some limitations, in that it does not handle functions. See https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm for more information, including an alternative algorithm in JS which gets you part of the way there.

请参考http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#为W3C“安全传递结构化数据”算法提供的结构化数据,旨在通过浏览器实现将数据传递给web workers。但是,它有一些限制,因为它不处理函数。请参阅https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm以获取更多信息,包括在JS中使用的另一种算法,它可以让您了解其中的一部分。