-
Notifications
You must be signed in to change notification settings - Fork 27.5k
fix(angular.copy): support circular references #7618
Conversation
Thanks for the PR! Please check the items below to help us merge this faster. See the contributing docs for more information.
If you need to make changes to your pull request, you can update the commit with Thanks again for your help! |
@@ -757,7 +757,7 @@ function isLeafNode (node) { | |||
</file> | |||
</example> | |||
*/ | |||
function copy(source, destination) { | |||
function copy(source, destination, stackSource, stackDest) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not so sure about having the stack*
parameters public.
Maybe a private version of .copy
should be created and used internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it really hurts to expose them, we could separate it but all it would do is add an extra function call and make the code a bit bigger --- probably not worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to what cait said. just not document them.
I feel like this is a potential breaking change, but lets see what happens :> it maybe won't break anyones applications |
stackDest = stackDest || []; | ||
|
||
var index = indexOf(stackSource, source); | ||
if (index !== -1) return stackDest[index]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@IgorMinar is it out of the question to use $$hashKey
for objects copied in this way? it would certainly be quicker than this, but it seems wrong to mess with peoples objects. Could do it and see if people complain, though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can't mess with the objects here.
lgtm |
@rodyhaddad - thanks for raising this in response to #7592. Per my latest comment on #7592, my stab at implementing this made The side effect of it not being the default behaviour is that every caller needs to update (including places in core) Am I missing something here? Seems like a safe, backwards compatible change, on the basis that any previous call to |
Sorry for the noise. To clarify my last point: I was trying to say that I think that making this enabled by default is "a safe, backwards compatible change...." Hence why my implementation was such. |
@myitcv while enabling it by default is backward compatible, we put the support of circular references behind a flag for performance reasons. Most uses of We updated the $digest and the $parse bindonce to turn on the circular reference support when copying user defined values, which I believe will solve your initial problem. And no worries about the noise, you asked for clarifications, so 👍 |
… it where possible In many cases, we want a shallow copy instead of a full copy
Actually, I think he's right --- since the only way to not be affected by circular references when using copy is to just use shallowCopy instead (which will never recursively copy anything). So it probably should be the default behaviour, and everything that legitimately doesn't need to care should simply use shallowCopy |
@rodyhaddad angular.resource has its own implementation of shallowCopy (or rather, based on it), it's a pretty trivial routine, and is not difficult for modules to implement on their own if it's not made public |
@rodyhaddad - are the performance implications that severe? (I ask that without any reference to any numbers...) If they are, then I would argue that we (and that's all users of My use case is, I believe, a sensible one - I The Unless you want the developer to flag on an object that circular reference support should be enabled. Via something like: var x = {a: 123};
x.$copy_circular_reference_support = true;
var y = angular.copy(x);
... with the corresponding code change in That's a rather long rambling argument in favour of making this be 'on' by default 👍 |
On reflection, scrap that suggestion on the I would bolster an earlier point I made to say that not only should use of |
I talked more with @IgorMinar about this, what we will do is:
Edit: hm, #2 doesn't really work, because angular.copy also deletes the old properties. angular.extend does not. |
… it where possible In many cases, we want a shallow copy instead of a full copy Closes #7618
Thanks @rodyhaddad and @caitp |
This PR is in response of #7592
I broke it into two parts:
angular.copy
support circular references. This is useful for the digest loop and for $parse's bind-once feature. We're deeply copying user defined objects, which will make.copy
hit the maximum call stack if it can't handle circular references..copy
is now heavier, shallowCopy can take its place in many scenarios. But it needs to handlearrays and primitives to do the full job (mainly for ngClass)