How to properly clone a JavaScript object?
P粉334721359
2023-08-23 12:26:59
<p>I have an object <code>x</code>. I want to copy it as an object <code>y</code> so that changes to <code>y</code> do not modify <code>x</code>. I realized that copying an object derived from a built-in JavaScript object would create extra, unwanted properties. This isn't a problem since I'm copying one of my own text-constructed objects. </p>
<p>How to properly clone a JavaScript object? </p>
If you are not using Date, Function, Undefined, regExp or Infinity in the object, a very simple line is
JSON.parse(JSON.stringify(object)):
This applies to all types of objects including objects, arrays, strings, booleans and numbers.
See also this article about the Structured Cloning Algorithm Browser , used when publishing messages to or from workers. It also includes deep cloning functionality.
Updated 2022
There is a new JS standard called Structured Cloning. It works in many browsers (see Can I use it).
Old Answer
Doing this with any object in JavaScript is never going to be simple or straightforward. You'll run into the problem of incorrectly getting properties from the object's prototype, which should remain in the prototype instead of being copied to the new instance. For example, if you were to add a
clone
method toObject.prototype
(as some answers suggest), you would need to explicitly skip that property. But what if there are other additional methods added inObject.prototype
or other intermediate prototypes that you don't know about? In this case, you are copying a property that shouldn't be copied, so you need to use thehasOwnProperty
method.In addition to non-enumerable properties, you also run into a trickier problem when you try to copy an object with hidden properties. For example,
prototype
is a hidden attribute of a function. Additionally, the object's prototype is referenced through the property__proto__
, which is also hidden and is not copied by for/in loops that iterate over the source object's properties. I think __proto__ may be specific to Firefox's JavaScript interpreter and may be different in other browsers, but you get the idea. Not everything is enumerable. If you know the name of the hidden property you can copy it, but I don't know of any way to discover it automatically.Another obstacle in the search for an elegant solution is the problem of setting up prototypal inheritance correctly. If the source object's prototype is
The date string forObject
, then just create a new generic object using{}
, but if the source object's prototype isObject
some descendant code>, then you will lose other members in that prototype that were skipped using thehasOwnProperty
filter, or other members in the prototype that were not 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 the properties, but you still won't get the non-enumerable properties. For example, theDate code>
object stores its data as hidden members:d1
will be 5 seconds later thand2
. The way to make oneDate
identical to another is to call thesetTime
method, but this is specific to theDate
class. I don't think there's a foolproof universal solution to this problem, although I'm happy to be wrong!When I had to implement a general deep copy, I finally compromised and assumed that I just needed to copy a normal
Object
,Array
,Date代码>,String代码>, Number代码>, or Boolean代码>. The last 3 types are immutable so I can perform shallow copies without worrying about it changing. I further assume that any element contained in
Object
orArray
will also be one of the 6 simple types in this list. This can be done with code like this:As long as the data in the object and array form a tree structure, the above function is sufficient for the 6 simple types I mentioned. That is, the same data in the object is referenced no more than once. For example:
It can't handle any JavaScript objects, but it may be sufficient for many purposes, as long as you don't think it will only work with anything you throw at it.