Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix(copy): add support for String/Boolean/Number object types #13641

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 33 additions & 15 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -881,22 +881,10 @@ function copy(source, destination) {
}

var needsRecurse = false;
var destination;
var destination = copyType(source);

if (isArray(source)) {
destination = [];
needsRecurse = true;
} else if (isTypedArray(source)) {
destination = new source.constructor(source);
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
destination.lastIndex = source.lastIndex;
} else if (isFunction(source.cloneNode)) {
destination = source.cloneNode(true);
} else {
destination = Object.create(getPrototypeOf(source));
if (destination === undefined) {
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
needsRecurse = true;
}

Expand All @@ -907,6 +895,36 @@ function copy(source, destination) {
? copyRecurse(source, destination)
: destination;
}

function copyType(source) {
switch (toString.call(source)) {
case '[object Int8Array]':
case '[object Int16Array]':
case '[object Int32Array]':
case '[object Float32Array]':
case '[object Float64Array]':
case '[object Uint8Array]':
case '[object Uint8ClampedArray]':
case '[object Uint16Array]':
case '[object Uint32Array]':
return new source.constructor(source);

case '[object Boolean]':
case '[object Number]':
case '[object String]':
case '[object Date]':
return new source.constructor(source.valueOf());

case '[object RegExp]':
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
re.lastIndex = source.lastIndex;
return re;
}

if (isFunction(source.cloneNode)) {
return source.cloneNode(true);
}
}
}

/**
Expand Down
39 changes: 39 additions & 0 deletions test/AngularSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,45 @@ describe('angular', function() {
expect(dest.c).toBe(3);
expect(Object.keys(dest)).toEqual(['a', 'b', 'c']);
});

it('should copy String() objects', function() {
/*jshint -W053 */
var obj = new String('foo');
/*jshint +W053 */
var dest = copy(obj);
expect(dest).not.toBe(obj);
expect(isObject(dest)).toBe(true);
expect(dest.valueOf()).toBe(obj.valueOf());
});

it('should copy Boolean() objects', function() {
/*jshint -W053 */
var obj = new Boolean(true);
/*jshint +W053 */
var dest = copy(obj);
expect(dest).not.toBe(obj);
expect(isObject(dest)).toBe(true);
expect(dest.valueOf()).toBe(obj.valueOf());
});

it('should copy Number() objects', function() {
/*jshint -W053 */
var obj = new Number(42);
/*jshint +W053 */
var dest = copy(obj);
expect(dest).not.toBe(obj);
expect(isObject(dest)).toBe(true);
expect(dest.valueOf()).toBe(obj.valueOf());
});

it('should copy falsy String/Boolean/Number objects', function() {
/*jshint -W053 */
expect(copy(new String('')).valueOf()).toBe('');
expect(copy(new Boolean(false)).valueOf()).toBe(false);
expect(copy(new Number(0)).valueOf()).toBe(0);
expect(copy(new Number(NaN)).valueOf()).toBeNaN();
/*jshint +W053 */
});
});

describe("extend", function() {
Expand Down