From a87135bb43223391ee9ed88dd0c8f6b774b9770f Mon Sep 17 00:00:00 2001 From: rodyhaddad Date: Wed, 28 May 2014 12:02:37 -0700 Subject: [PATCH] chore(shallowCopy): handle arrays and primitives, and switch to using it where possible In many cases, we want a shallow copy instead of a full copy Closes #7618 --- src/Angular.js | 22 ++++++++++++++-------- src/ng/directive/ngClass.js | 2 +- src/ng/directive/select.js | 2 +- src/ng/http.js | 8 ++++---- src/ng/sce.js | 2 +- test/AngularSpec.js | 19 +++++++++++++++++++ 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/Angular.js b/src/Angular.js index a6f8ef71fb9a..f9d490d4a043 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -799,20 +799,26 @@ function copy(source, destination) { } /** - * Create a shallow copy of an object + * Creates a shallow copy of an object, an array or a primitive */ function shallowCopy(src, dst) { - dst = dst || {}; + if (isArray(src)) { + dst = dst || []; - for(var key in src) { - // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src - // so we don't need to worry about using our custom hasOwnProperty here - if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) { - dst[key] = src[key]; + for ( var i = 0; i < src.length; i++) { + dst[i] = src[i]; + } + } else if (isObject(src)) { + dst = dst || {}; + + for (var key in src) { + if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) { + dst[key] = src[key]; + } } } - return dst; + return dst || src; } diff --git a/src/ng/directive/ngClass.js b/src/ng/directive/ngClass.js index 82aaad893497..ac5c7286220e 100644 --- a/src/ng/directive/ngClass.js +++ b/src/ng/directive/ngClass.js @@ -78,7 +78,7 @@ function classDirective(name, selector) { updateClasses(oldClasses, newClasses); } } - oldVal = copy(newVal); + oldVal = shallowCopy(newVal); } } }; diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js index a6ff78ce89d1..800c783a55a9 100644 --- a/src/ng/directive/select.js +++ b/src/ng/directive/select.js @@ -283,7 +283,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { // we need to work of an array, so we need to see if anything was inserted/removed scope.$watch(function selectMultipleWatch() { if (!equals(lastView, ctrl.$viewValue)) { - lastView = copy(ctrl.$viewValue); + lastView = shallowCopy(ctrl.$viewValue); ctrl.$render(); } }); diff --git a/src/ng/http.js b/src/ng/http.js index 5ffc8365acf2..f07ae847ac70 100644 --- a/src/ng/http.js +++ b/src/ng/http.js @@ -111,9 +111,9 @@ function $HttpProvider() { common: { 'Accept': 'application/json, text/plain, */*' }, - post: copy(CONTENT_TYPE_APPLICATION_JSON), - put: copy(CONTENT_TYPE_APPLICATION_JSON), - patch: copy(CONTENT_TYPE_APPLICATION_JSON) + post: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), + put: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), + patch: shallowCopy(CONTENT_TYPE_APPLICATION_JSON) }, xsrfCookieName: 'XSRF-TOKEN', @@ -874,7 +874,7 @@ function $HttpProvider() { } else { // serving from cache if (isArray(cachedResp)) { - resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]), cachedResp[3]); + resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]); } else { resolvePromise(cachedResp, 200, {}, 'OK'); } diff --git a/src/ng/sce.js b/src/ng/sce.js index d9b70ccf96b3..f8ea2e2eadd4 100644 --- a/src/ng/sce.js +++ b/src/ng/sce.js @@ -737,7 +737,7 @@ function $SceProvider() { 'document. See http://docs.angularjs.org/api/ng.$sce for more information.'); } - var sce = copy(SCE_CONTEXTS); + var sce = shallowCopy(SCE_CONTEXTS); /** * @ngdoc method diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 12142a918fc1..28d2ad5e7603 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -218,6 +218,25 @@ describe('angular', function() { expect(clone.hello).toBeUndefined(); expect(clone.goodbye).toBe("world"); }); + + it('should handle arrays', function() { + var original = [{}, 1], + clone = []; + + var aCopy = shallowCopy(original); + expect(aCopy).not.toBe(original); + expect(aCopy).toEqual(original); + expect(aCopy[0]).toBe(original[0]); + + expect(shallowCopy(original, clone)).toBe(clone); + expect(clone).toEqual(original); + }); + + it('should handle primitives', function() { + expect(shallowCopy('test')).toBe('test'); + expect(shallowCopy(3)).toBe(3); + expect(shallowCopy(true)).toBe(true); + }); }); describe('elementHTML', function() {