fix(angular.copy): support circular references in the value being copied

Closes #7618
This commit is contained in:
rodyhaddad
2014-05-28 12:14:08 -07:00
parent a87135bb43
commit 083f496d46
4 changed files with 45 additions and 7 deletions

View File

@@ -757,7 +757,7 @@ function isLeafNode (node) {
</file>
</example>
*/
function copy(source, destination) {
function copy(source, destination, stackSource, stackDest) {
if (isWindow(source) || isScope(source)) {
throw ngMinErr('cpws',
"Can't copy! Making copies of Window or Scope instances is not supported.");
@@ -767,22 +767,40 @@ function copy(source, destination) {
destination = source;
if (source) {
if (isArray(source)) {
destination = copy(source, []);
destination = copy(source, [], stackSource, stackDest);
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source);
} else if (isObject(source)) {
destination = copy(source, {});
destination = copy(source, {}, stackSource, stackDest);
}
}
} else {
if (source === destination) throw ngMinErr('cpi',
"Can't copy! Source and destination are identical.");
stackSource = stackSource || [];
stackDest = stackDest || [];
if (isObject(source)) {
var index = indexOf(stackSource, source);
if (index !== -1) return stackDest[index];
stackSource.push(source);
stackDest.push(destination);
}
var result;
if (isArray(source)) {
destination.length = 0;
for ( var i = 0; i < source.length; i++) {
destination.push(copy(source[i]));
result = copy(source[i], null, stackSource, stackDest);
if (isObject(source[i])) {
stackSource.push(source[i]);
stackDest.push(result);
}
destination.push(result);
}
} else {
var h = destination.$$hashKey;
@@ -790,10 +808,16 @@ function copy(source, destination) {
delete destination[key];
});
for ( var key in source) {
destination[key] = copy(source[key]);
result = copy(source[key], null, stackSource, stackDest);
if (isObject(source[key])) {
stackSource.push(source[key]);
stackDest.push(result);
}
destination[key] = result;
}
setHashKey(destination,h);
}
}
return destination;
}

View File

@@ -1072,7 +1072,7 @@ function $ParseProvider() {
self.$$postDigestQueue.push(function () {
// create a copy if the value is defined and it is not a $sce value
if ((stable = isDefined(lastValue)) && !lastValue.$$unwrapTrustedValue) {
lastValue = copy(lastValue);
lastValue = copy(lastValue, null);
}
});
}

View File

@@ -702,7 +702,7 @@ function $RootScopeProvider(){
&& isNaN(value) && isNaN(last)))) {
dirty = true;
lastDirtyWatch = watch;
watch.last = watch.eq ? copy(value) : value;
watch.last = watch.eq ? copy(value, null) : value;
watch.fn(value, ((last === initWatchVal) ? value : last), current);
if (ttl < 5) {
logIdx = 4 - ttl;