Skip to content

Commit 7b51243

Browse files
jbedardlgalfaso
authored andcommitted
fix(copy): add support for String/Boolean/Number object types
Closes: angular#13641
1 parent 798fb18 commit 7b51243

File tree

2 files changed

+72
-15
lines changed

2 files changed

+72
-15
lines changed

src/Angular.js

+33-15
Original file line numberDiff line numberDiff line change
@@ -881,22 +881,10 @@ function copy(source, destination) {
881881
}
882882

883883
var needsRecurse = false;
884-
var destination;
884+
var destination = copyType(source);
885885

886-
if (isArray(source)) {
887-
destination = [];
888-
needsRecurse = true;
889-
} else if (isTypedArray(source)) {
890-
destination = new source.constructor(source);
891-
} else if (isDate(source)) {
892-
destination = new Date(source.getTime());
893-
} else if (isRegExp(source)) {
894-
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
895-
destination.lastIndex = source.lastIndex;
896-
} else if (isFunction(source.cloneNode)) {
897-
destination = source.cloneNode(true);
898-
} else {
899-
destination = Object.create(getPrototypeOf(source));
886+
if (destination === undefined) {
887+
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
900888
needsRecurse = true;
901889
}
902890

@@ -907,6 +895,36 @@ function copy(source, destination) {
907895
? copyRecurse(source, destination)
908896
: destination;
909897
}
898+
899+
function copyType(source) {
900+
switch (toString.call(source)) {
901+
case '[object Int8Array]':
902+
case '[object Int16Array]':
903+
case '[object Int32Array]':
904+
case '[object Float32Array]':
905+
case '[object Float64Array]':
906+
case '[object Uint8Array]':
907+
case '[object Uint8ClampedArray]':
908+
case '[object Uint16Array]':
909+
case '[object Uint32Array]':
910+
return new source.constructor(source);
911+
912+
case '[object Boolean]':
913+
case '[object Number]':
914+
case '[object String]':
915+
case '[object Date]':
916+
return new source.constructor(source.valueOf());
917+
918+
case '[object RegExp]':
919+
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
920+
re.lastIndex = source.lastIndex;
921+
return re;
922+
}
923+
924+
if (isFunction(source.cloneNode)) {
925+
return source.cloneNode(true);
926+
}
927+
}
910928
}
911929

912930
/**

test/AngularSpec.js

+39
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,45 @@ describe('angular', function() {
471471
expect(dest.c).toBe(3);
472472
expect(Object.keys(dest)).toEqual(['a', 'b', 'c']);
473473
});
474+
475+
it('should copy String() objects', function() {
476+
/*jshint -W053 */
477+
var obj = new String('foo');
478+
/*jshint +W053 */
479+
var dest = copy(obj);
480+
expect(dest).not.toBe(obj);
481+
expect(isObject(dest)).toBe(true);
482+
expect(dest.valueOf()).toBe(obj.valueOf());
483+
});
484+
485+
it('should copy Boolean() objects', function() {
486+
/*jshint -W053 */
487+
var obj = new Boolean(true);
488+
/*jshint +W053 */
489+
var dest = copy(obj);
490+
expect(dest).not.toBe(obj);
491+
expect(isObject(dest)).toBe(true);
492+
expect(dest.valueOf()).toBe(obj.valueOf());
493+
});
494+
495+
it('should copy Number() objects', function() {
496+
/*jshint -W053 */
497+
var obj = new Number(42);
498+
/*jshint +W053 */
499+
var dest = copy(obj);
500+
expect(dest).not.toBe(obj);
501+
expect(isObject(dest)).toBe(true);
502+
expect(dest.valueOf()).toBe(obj.valueOf());
503+
});
504+
505+
it('should copy falsy String/Boolean/Number objects', function() {
506+
/*jshint -W053 */
507+
expect(copy(new String('')).valueOf()).toBe('');
508+
expect(copy(new Boolean(false)).valueOf()).toBe(false);
509+
expect(copy(new Number(0)).valueOf()).toBe(0);
510+
expect(copy(new Number(NaN)).valueOf()).toBeNaN();
511+
/*jshint +W053 */
512+
});
474513
});
475514

476515
describe("extend", function() {

0 commit comments

Comments
 (0)