fix(angular.copy): support circular references

This PR is in response of #7592

I broke it into two parts:

1. Making `angular.copy` support circular references. This is useful for [the digest loop](https://github.com/angular/angular.js/blob/4eb9522f902f31a73b762ba0222cf3ad5d6c0b32/src/ng/rootScope.js#L693) and for [$parse's bind-once feature](https://github.com/angular/angular.js/blob/4eb9522f902f31a73b762ba0222cf3ad5d6c0b32/src/ng/parse.js#L1075). We're deeply copying user defined objects, which will make `.copy` hit the maximum call stack if it can't handle circular references.

2. Since `.copy` is now _heavier_, shallowCopy can take its place in many scenarios. But it needs to handle 
arrays and primitives to do the full job (mainly for ngClass)