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

Commit a097aa9

Browse files
committedDec 9, 2014
fix(orderBy): do not try to call valueOf/toString on null
8bfeddb added changes to make relational operator work as it normally would in JS --- unfortunately, this broke due to my failure to account for typeof null being "object". This refactoring attempts to convert object values to primitives still, in a fashion similar to the SortCompare (and subsequently the ToString() algorithm) from ES, in order to account for `null` and also simplify code to some degree. BREAKING CHANGE: Previously, if either value being compared in the orderBy comparator was null or undefined, the order would not change. Now, this order behaves more like Array.prototype.sort, which by default pushes `null` behind objects, due to `n` occurring after `[` (the first characters of their stringified forms) in ASCII / Unicode. If `toString` is customized, or does not exist, the behaviour is undefined. Closes #10385 Closes #10386
1 parent b3dfb38 commit a097aa9

File tree

2 files changed

+59
-19
lines changed

2 files changed

+59
-19
lines changed
 

‎src/ng/filter/orderBy.js

+27-19
Original file line numberDiff line numberDiff line change
@@ -160,29 +160,37 @@ function orderByFilter($parse) {
160160
? function(a, b) {return comp(b,a);}
161161
: comp;
162162
}
163+
164+
function isPrimitive(value) {
165+
switch (typeof value) {
166+
case 'number': /* falls through */
167+
case 'boolean': /* falls through */
168+
case 'string':
169+
return true;
170+
default:
171+
return false;
172+
}
173+
}
174+
175+
function objectToString(value) {
176+
if (value === null) return 'null';
177+
if (typeof value.toString === 'function') {
178+
value = value.toString();
179+
if (isPrimitive(value)) return value;
180+
}
181+
if (typeof value.valueOf === 'function') {
182+
value = value.valueOf();
183+
if (isPrimitive(value)) return value;
184+
}
185+
return '';
186+
}
187+
163188
function compare(v1, v2) {
164189
var t1 = typeof v1;
165190
var t2 = typeof v2;
166-
// Prepare values for Abstract Relational Comparison
167-
// (http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5):
168-
// If the resulting values are identical, return 0 to prevent
169-
// incorrect re-ordering.
170191
if (t1 === t2 && t1 === "object") {
171-
// If types are both numbers, emulate abstract ToPrimitive() operation
172-
// in order to get primitive values suitable for comparison
173-
t1 = typeof (v1.valueOf ? v1 = v1.valueOf() : v1);
174-
t2 = typeof (v2.valueOf ? v2 = v2.valueOf() : v2);
175-
if (t1 === t2 && t1 === "object") {
176-
// Object.prototype.valueOf will return the original object, by
177-
// default. If we do not receive a primitive value, use ToString()
178-
// instead.
179-
t1 = typeof (v1.toString ? v1 = v1.toString() : v1);
180-
t2 = typeof (v2.toString ? v2 = v2.toString() : v2);
181-
182-
// If the end result of toString() for each item is the same, do not
183-
// perform relational comparison, and do not re-order objects.
184-
if (t1 === t2 && v1 === v2 || t1 === "object") return 0;
185-
}
192+
v1 = objectToString(v1);
193+
v2 = objectToString(v2);
186194
}
187195
if (t1 === t2) {
188196
if (t1 === "string") {

‎test/ng/filter/orderBySpec.js

+32
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,22 @@ describe('Filter: orderBy', function() {
125125
});
126126
expect(orderBy(array)).toEqualData(array);
127127
});
128+
129+
130+
it('should sort nulls as Array.prototype.sort', function() {
131+
var array = [
132+
{ id: 2 },
133+
null,
134+
{ id: 3 },
135+
null
136+
];
137+
expect(orderBy(array)).toEqualData([
138+
{ id: 2 },
139+
{ id: 3 },
140+
null,
141+
null
142+
]);
143+
});
128144
});
129145

130146

@@ -252,5 +268,21 @@ describe('Filter: orderBy', function() {
252268
});
253269
expect(orderBy(array)).toEqualData(array);
254270
});
271+
272+
273+
it('should sort nulls as Array.prototype.sort', function() {
274+
var array = [
275+
{ id: 2 },
276+
null,
277+
{ id: 3 },
278+
null
279+
];
280+
expect(orderBy(array)).toEqualData([
281+
{ id: 2 },
282+
{ id: 3 },
283+
null,
284+
null
285+
]);
286+
});
255287
});
256288
});

0 commit comments

Comments
 (0)