From 4815135dbf75f7b5607495f411a49b45b049d696 Mon Sep 17 00:00:00 2001 From: Viktor Zozulyak Date: Wed, 8 Feb 2017 22:02:06 +0100 Subject: [PATCH] fix(angular.copy): copy own non-enumerable properties copying object without own non-enumerable properties is non-consistent and can lead to bugs fixes #15692 --- src/Angular.js | 11 +++++++++++ test/AngularSpec.js | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/Angular.js b/src/Angular.js index 48c31ea1a0b9..a7e8c01c68b1 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -941,6 +941,17 @@ function copy(source, destination, maxDepth) { for (key in source) { destination[key] = copyElement(source[key], maxDepth); } + // don't use Object.getOwnPropertyNames with RegExp to avoid copying RegExp lastIndex property + } else if (isObject(source) && typeof Object.getOwnPropertyNames === 'function' && !isRegExp(source)) { + Object.getOwnPropertyNames(source).forEach(function(key) { + var elementCopy = copyElement(source[key], maxDepth); + + if (source.propertyIsEnumerable(key)) { + destination[key] = elementCopy; + } else { + Object.defineProperty(destination, key, {value: elementCopy}); + } + }); } else if (source && typeof source.hasOwnProperty === 'function') { // Slow path, which must rely on hasOwnProperty for (key in source) { diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 9aaa2f5b8f83..a9426b99eb5c 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -620,6 +620,17 @@ describe('angular', function() { expect(dest).toEqual({a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}}); }); + it('should copy own non-enumerable properties keeping them non-enumerable', function() { + var getter = function() { return Math.random(); }; + var source = {}; + var dest; + + Object.defineProperty(source, 'getter', {value: getter}); + dest = copy(source); + expect(dest.getter).toBe(getter); + expect(dest.propertyIsEnumerable('getter')).toBe(false); + }); + they('should copy source and ignore max depth when maxDepth = $prop', [NaN, null, undefined, true, false, -1, 0], function(maxDepth) { var source = {a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}};