标签云

微信群

扫码加入我们

WeChat QR Code


Eval is not evil. Using eval poorly is. If you are afraid of its side effects you are using it wrong. The side effects you fear are the reasons to use it. Did any one by the way actually answer your question?

2018年12月16日38分03秒

Cloning objects is a tricky business, especially with custom objects of arbitrary collections. Which probably why there is no out-of-the box way to do it.

2018年12月17日38分03秒

eval() is generally a bad idea because many Javascript engine's optimisers have to turn off when dealing with variables that are set via eval. Just having eval() in your code can lead to worse performance.

2018年12月16日38分03秒

Possible duplicate of Most elegant way to clone a JavaScript object

2018年12月17日38分03秒

here's a performance comparison between the most common types of cloning objects: jsben.ch/#/t917Z

2018年12月17日38分03秒

For those who didn't realize, John Resig's answer was probably intended as a kind of response/clarification to ConroyP's answer, instead of a direct reply to the question.

2018年12月17日38分03秒

ThiefMaster github.com/jquery/jquery/blob/master/src/core.js at line 276 (there's a bit of code that does something else but the code for "how to do this in JS" is there :)

2018年12月17日38分03秒

Here's the JS code behind the jQuery deep copy, for anyone interested: github.com/jquery/jquery/blob/master/src/core.js#L265-327

2018年12月17日38分03秒

Woah! Just to be super-clear: no idea why this response was picked as the right answer, this was a reply to responses given below: stackoverflow.com/a/122190/6524 (which was recommending .clone(), which is not the right code to be using in this context). Unfortunately this question has gone through so many revisions the original discussion is no longer even apparent! Please just follow Corban's advice and write a loop or copy the properties directly over to a new object, if you care about speed. Or test it out for yourself!

2018年12月17日38分03秒

How would one do this without using jQuery?

2018年12月17日38分03秒

trysis Object.create is not cloning the object, is using the prototype object... jsfiddle.net/rahpuser/yufzc1jt/2

2018年12月17日38分03秒

This method will also remove the keys from your object, which have functions as their values, because the JSON doesn't support functions.

2018年12月17日38分03秒

Also keep in mind that using JSON.parse(JSON.stringify(obj)) on Date Objects will also convert the date back to UTC in the string representation in the ISO8601 format.

2018年12月17日38分03秒

JSON approach also chokes on circular references.

2018年12月17日38分03秒

velop , Object.assign({}, objToClone) seems like it does a shallow clone though -- using it while playing around in the dev tools console, the object clone still pointed to a reference of the cloned object. So I don't think it's really applicable here.

2018年12月17日38分03秒

the con of this approach as I've just found is if your object has any functions (mine has internal getters & setters) then these are lost when stringified.. If that's all you need this method is fine..

2018年12月17日38分03秒

Jason, The reason why this method is slower than shallow copying (on a deep object) is that this method, by definition, deep copies. But since JSON is implemented in native code (in most browsers), this will be considerably faster than using any other javascript-based deep copying solution, and may sometimes be faster than a javascript-based shallow copying technique (see: jsperf.com/cloning-an-object/79).

2018年12月17日38分03秒

JSON.stringify({key: undefined}) //=> "{}"

2018年12月17日38分03秒

this technique is going to destroy also all Date objects that are stored inside the object, converting them to string form.

2018年12月17日38分03秒

It will fail to copy anything that is not part of the JSON spec (json.org)

2018年12月17日38分03秒

rynah I just looked through the spec again and you're right: the history.pushState() and history.replaceState() methods both synchronously set history.state to a structured clone of their first argument. A little weird, but it works. I'm updating my answer now.

2018年12月17日38分03秒

This is just so wrong! That API is not meant to be used this way.

2018年12月17日38分03秒

As the guy who implemented pushState in Firefox, I feel an odd mix of pride and revulsion at this hack. Well done, guys.

2018年12月17日38分03秒

The JQuery solution will work for DOM elements but not just any Object. Mootools has the same limit. Wish they had a generic "clone" for just any object... The recursive solution should work for anything. It's probably the way to go.

2018年12月17日38分03秒

This function breaks if the object being cloned has a constructor that requires parameters. It seems like we can change it to "var temp = new Object()" and have it work in every case, no?

2018年12月17日38分03秒

Andrew, if you change it to var temp = new Object(), then your clone won't have the same prototype as the original object. Try using: 'var newProto = function(){}; newProto.prototype = obj.constructor; var temp = new newProto();'

2018年12月17日38分03秒

Similar to limscoder's answer, see my answer below on how to do this without calling the constructor: stackoverflow.com/a/13333781/560114

2018年12月17日38分03秒

For objects that contain references to sub-parts (i.e., networks of objects), this does not work: If two references point to the same sub-object, the copy contains two different copies of it. And if there are recursive references, the function will never terminate (well, at least not in the way you want it :-) For these general cases, you have to add a dictionary of objects already copied, and check whether you already copied it... Programming is complex when you use a simple language

2018年12月17日38分03秒

This doesn't recursively copy so doesn't really offer a solution to the problem of cloning an object.

2018年12月17日38分03秒

This method worked, although I tested a few and _.extend({}, (obj)) was BY FAR the fastest: 20x faster than JSON.parse and 60% faster than Object.assign, for example. It copies all sub-objects quite well.

2018年12月17日38分03秒

mwhite there is a difference between clone and deep-clone. This answer does in fact clone, but it doesn't deep-clone.

2018年12月17日38分03秒

the op asked for deep clone. this doesn't do deep clone.

2018年12月17日38分03秒

wow so many Object.assign responses without even reading the op's question...

2018年12月17日38分03秒

what about var obj = {} and obj.a = obj

2018年12月17日38分03秒

I don't understand this function. Suppose from.constructor is Date for example. How would the third if test be reached when the 2nd if test would succeed & cause the function to return (since Date != Object && Date != Array)?

2018年12月17日38分03秒

AdamMcKee Because javascript argument passing and variable assignment is tricky. This approach works great, including dates (which indeed are handled by the second test) - fiddle to test here: jsfiddle.net/zqv9q9c6.

2018年12月16日38分03秒

*I meant "parameter assignment" (within a function body), not "variable assignment". Although it helps to understand both thoroughly.

2018年12月16日38分03秒

NickSweeting: Try - may be it works. If not - fix it and update the answer. That's how it works here in community:)

2018年12月16日38分03秒

This does not seem right. cloneObject({ name: null }) => {"name":{}}

2018年12月17日38分03秒

This is due to another dumb thing in javascript typeof null > "object" but Object.keys(null) > TypeError: Requested keys of a value that is not an object. change the condition to if(typeof(obj[i])=="object" && obj[i]!=null)

2018年12月17日38分03秒

This will assign inherited enumerable properties of obj directly to the clone, and assumes that obj is a plain Object.

2018年12月17日38分03秒

This also messes up arrays, which get converted to objects with numeric keys.

2018年12月17日38分03秒

Not a problem if you don't use null.

2018年12月17日38分03秒

I tested a few and _.extend({}, (obj)) was BY FAR the fastest: 20x faster than JSON.parse and 60% faster than Object.assign, for example. It copies all sub-objects quite well.

2018年12月17日38分03秒

NicoDurand - Are your performance tests online?

2018年12月17日38分03秒

All of your examples are shallow, one level. This is not a good answer. The Question was regarding deep cloning i.e. at least two levels.

2018年12月17日38分03秒

A deep copy is when an object is copied in its' entirety without the use of reference pointers to other objects. The techniques under the section "Deep copy an array of objects", such as jQuery.extend() and the custom function (which is recursive) copy objects with "at least two levels". So, no not all the examples are "one level" copies.

2018年12月17日38分03秒

I like your custom copy function, but you should exclude null values, otherwise all null values are being converted to objects, i.e.: out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;

2018年12月17日38分03秒

This answer is not really relevant because the question is: given instance b how does one create copy c WHILE not knowing about factory a or not wanting to use factory a. The reason one may not want to use the factory is that after instantiation b may have been initialised with additional data (e.g. user input).

2018年12月17日38分03秒

It's true that this is not really an answer to the question, but I think it's important that it be here because it is the answer to the question I suspect many of the people coming here are really meaning to ask.

2018年12月17日38分03秒

Sorry guys, I don't really understand why so many upvotes. Cloning an object is a pretty clear concept, you cone an object from ANOTHER object, and it doesn't have much to do with creating a new one with the factory pattern.

2018年12月17日38分03秒

While this works for predefined objects, "cloning" in this manner will not recognize new properties added to the original object. If you create a, add a new property to a, then create b. b will not have the new property. Essentially the factory pattern is immutable to new properties. This is not paradigmatically cloning. See: jsfiddle.net/jzumbrun/42xejnbx

2018年12月16日38分03秒

I think this is good advice, generally, since instead of using const defaultFoo = { a: { b: 123 } }; you can go const defaultFoo = () => ({ a: { b: 123 } }; and your problem is solved. However, it really isn't an answer to the question. It might have made more sense as a comment on the question, not a full answer.

2018年12月17日38分03秒

npm clone has been invaluable to me for cloning arbitrarily nested objects. This is the right answer.

2018年12月17日38分03秒

what is the performance of your lib compared to let's say JSON.parse(JSON.stringify(obj))?

2018年12月17日38分03秒

Here's a library that states that there are faster options. Haven't tested though.

2018年12月17日38分03秒

clone in underscore is not a deep clone in current version

2018年12月17日38分03秒

Thanks. yes as new doc for Underscore... clone_.clone(object) Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated. _.clone({name: 'moe'}); => {name: 'moe'};

2018年12月17日38分03秒

Object.assign does not deep copy. Example: var x = { a: { b: "c" } }; var y = Object.assign({}, x); x.a.b = "d". If this was deep copy, y.a.b would still be c, but it's now d.

2018年12月17日38分03秒

Object.assign() only clones the first level of properties!

2018年12月17日38分03秒

what is cloneSO() function?

2018年12月17日38分03秒

lodash has a cloneDeep method, it also support another param to clone to make it deep: lodash.com/docs#clone and lodash.com/docs#cloneDeep

2018年12月17日38分03秒

opensas agreed. Lodash is generally superior to underscore

2018年12月17日38分03秒

I advocate deleting this and all other answers which are just one-line references to a utility library's .clone(...) method. Every major library will have them, and the repeated brief non-detailed answers aren't useful to most visitors, who won't be using that particular library.

2018年12月17日38分03秒

Is there anything wrong with this answer? It's more useful as being a standalone solution, yet simple; but jQuery solution is more popular. Why is that?

2018年12月17日38分03秒

Yes please let me know. It seems to be working as intended, if there is some hidden breakage somewhere, I need to use a different solution.

2018年12月17日38分03秒

For a simple object, this is around 6 times slower in Chrome than the given answer, and gets much slower as the complexity of the object grows. It scales terribly and can bottleneck your application very quickly.

2018年12月17日38分03秒

You don't need data, just an understanding of what's going on. This cloning technique serializes the entire object in to a string, then parses that string serialization to build an object. Inherently that's just going to be a lot slower than simply re-arranging some memory (which is what the more sophisticated clones do). But with that being said, for small to medium-sized projects (depending on your definition of "medium-sized") who cares if it's even 1000x less efficient? If your objects are small and you don't clone them a ton 1000x of virtually nothing is still virtually nothing.

2018年12月17日38分03秒

Also, this method loses methods (or any stuff that is not allowed in JSON), plus - JSON.stringify will convert Date objects to strings, ... and not the other way around ;) Stay off this solution.

2018年12月17日38分03秒

The problem with method, that if you have sub objects within the obj, their references will be cloned, and not the values of every sub object.

2018年12月17日38分03秒

just make it recursive so the sub objects will be cloned deeply.

2018年12月17日38分03秒

just curious ... wont be the clone variable will have the pointers to the properties of the original object? because it seems no new memory allocation

2018年12月17日38分03秒

Yes. This is just a shallow copy, so the clone will point to the exact same objects pointed-to by the original object.

2018年12月17日38分03秒

correct me if I am wrong, but isn't that Crockford's beget function for prototypal inheritance? How does it apply to clone?

2018年12月17日38分03秒

Yes, I was afraid of this discussion: What is the practical difference between clone, copy and prototypal inheritance, when should you use each and which functions on this page are actually doing what? I found this SO page by googling "javascript copy object". What I was really looking for was the function above, so I came back to share. My guess is the asker was looking for this too.

2018年12月17日38分03秒

Difference between clone/copy and inheritance is, that - using your example, when I change a property of oldObject, the property also gets changed in newObject. If you make a copy, you can do what you want with oldObject without changing newObject.

2018年12月17日38分03秒

This will break the hasOwnProperty check so its a pretty hacky way to clone an object and will give you unexpected results.

2018年12月17日38分03秒

var extendObj = function(childObj, parentObj) { var tmpObj = function () {} tmpObj.prototype = parentObj.prototype; childObj.prototype = new tmpObj(); childObj.prototype.constructor = childObj; }; ... davidshariff.com/blog/javascript-inheritance-patterns

2018年12月17日38分03秒

I advocate deleting this and all other answers which are just one-line references to a utility library's .clone(...) method. Every major library will have them, and the repeated brief non-detailed answers aren't useful to most visitors, who won't be using that particular library.

2018年12月17日38分03秒

An easier way is to use _.merge({}, objA). If only lodash didn't mutate objects in the first place then the clone function wouldn't be necessary.

2018年12月17日38分03秒

Google searches for cloning JS objects refer to here. I'm using Lodash so this answer is relevant to me. Lets not go all "wikipedia deletionist" on answers please.

2018年12月17日38分03秒

In Node 9, JSON.parse(JSON.stringify(arrayOfAbout5KFlatObjects)) is a lot faster than _.deepClone(arrayOfAbout5KFlatObjects).

2018年12月17日38分03秒

This may be fine for simple objects, but it only copies property values. It does not touch the prototype chain and by using Object.keys it skips non-enumerable and inherited properties. Also, it loses property descriptors by doing direct assignment.

2018年12月17日38分03秒

If you copy the prototype too, you'd be missing only non-enumerables and property descriptors, yes? Pretty good. :)

2018年12月17日38分03秒

Performance aside, this is a really convenient way to shallow copy an object. I often use this to sort of fake rest properties in a destructuring assignment in my React components.

2018年12月17日38分03秒

or it might be used the same way as jQiery extend: angular.extend({},obj);

2018年12月17日38分03秒

Galvani: It should be noted that jQuery.extend and angular.extend are both shallow copies. angular.copy is a deep copy.

2018年12月17日38分03秒

as others have pointed out in comments to Resig's answer, if you want to clone an array-like object you change the {} to [] in the extend call, eg jQuery.extend(true, [], obj)

2018年12月17日38分03秒

JSON.stringify not work with functions

2018年12月17日38分03秒

I liked this approach but it doesn't handle dates properly; consider adding something like if(o instanceof Date) return new Date(o.valueOf()); after checking for null `

2018年12月17日38分03秒

Crashes on circular references.

2018年12月17日38分03秒

It converts primitives into wrapper objects, not a good solution in most cases.

2018年12月17日38分03秒

DanubianSailor - I don't think it does...it seems to return primitives right away from the start, and doesn't seem to be doing anything to them that would turn them into wrapper objects as they are returned.

2018年12月17日38分03秒

Object.assign() does not perform a deep copy

2018年12月17日38分03秒

thank you so much, Object.assign() method have updated

2018年12月17日38分03秒

you should add benchmarks for these; that would be very helpful

2018年12月17日38分03秒