From ccac2df93b7ae98da2a2e4f7662f4eb280c62c9a Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Thu, 7 May 2020 00:18:29 +0200 Subject: [PATCH 1/3] Document the use of operator < (#1768, #1834, #2042) --- index.html | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index e785d72eb..29c7ddb09 100644 --- a/index.html +++ b/index.html @@ -382,6 +382,12 @@ +
+ + Notes + +
+
Change Log @@ -734,6 +740,8 @@

Collection Functions (Arrays or Objects)

criterion by which the value is ranked. -Infinity is returned if list is empty, so an
isEmpty guard may be required. Non-numerical values in list will be ignored. + This function uses operator < + (note).

 var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
@@ -749,6 +757,8 @@ 

Collection Functions (Arrays or Objects)

criterion by which the value is ranked. Infinity is returned if list is empty, so an isEmpty guard may be required. Non-numerical values in list will be ignored. + This function uses operator < + (note).

 var numbers = [10, 5, 100, 2, 1000];
@@ -762,7 +772,8 @@ 

Collection Functions (Arrays or Objects)

Returns a (stably) sorted copy of list, ranked in ascending order by the results of running each value through iteratee. iteratee may also be the string name of the property to sort by (eg. - length). + length). This function uses operator < + (note).

 _.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
@@ -1091,7 +1102,9 @@ 

Array Functions

large array, and you know that the array is already sorted, pass true for isSorted to use a faster binary search ... or, pass a number as the third argument in order to look for the first matching value in the - array after the given index. + array after the given index. If isSorted is true, + this function uses operator < + (note).

 _.indexOf([1, 2, 3], 2);
@@ -1117,7 +1130,9 @@ 

Array Functions

should be inserted into the array in order to maintain the array's sorted order. If an iteratee function is provided, it will be used to compute the sort ranking of each value, including the value you pass. - The iteratee may also be the string name of the property to sort by (eg. length). + The iteratee may also be the string name of the property to sort by + (eg. length). This function uses operator < + (note).

 _.sortedIndex([10, 20, 30, 40, 50], 35);
@@ -2417,6 +2432,85 @@ 
         collection of functional helpers for Python, partially inspired by Underscore.
       

+

Notes

+ +

+ On using the < operator in JavaScript +
+ Underscore functions that depend on ordering, such as + _.sortBy and + _.sortedIndex, use + JavaScript’s built-in + relational operators, + specifically the “less than” operator <. It is + important to understand that these operators are only meaningful for + numbers and strings. You can throw any value to them, but JavaScript + will convert the operands to string or number first before performing + the actual comparison. +

+

+ If you use the relational operators naievely and pass an operand that + cannot be meaningfully converted to string or number, it ends up being + NaN by default. This frequently causes confusion because a + comparison with NaN always yields false: +

+
+1 < NaN // false
+NaN < 1 // false
+NaN == 1 // false
+'a' < NaN // false
+NaN < 'a' // false
+NaN == 'a' // false
+NaN < NaN // false
+NaN <= NaN // false!
+NaN === NaN // false!
+      
+

+ In the past, people have tried passing such operands to Underscore + functions as well. This invariably led to confusion, too. For example, + consider the following apparent inconsistency between _.sortBy + and _.sortedIndex (reported in + issue #1834): +

+
+_.sortBy([undefined, 1, undefined, 2]);
+// => [1, 2, undefined, undefined]
+_.sortedIndex([1, 2, undefined, undefined], undefined);
+// => 0; reporter expected 2
+      
+

+ The problem with this example, however is not that _.sortBy + and _.sortedIndex are inconsistent with each other, but that + unsortable values are being passed into the functions in the first + place. undefined is just one of the many possible values that + is converted to NaN. +

+

+ Take home point: make sure that ordering makes sense for your values. + Ideally, the values that you are sorting should either be all + (meaningfully convertible to) strings or all (meaningfully convertible + to) numbers. If this is not the case, you have two options: +

    +
  • + _.filter out all unsortable values + first. +
  • +
  • + Pick a target type, i.e., either string or number, and pass an + iteratee to your Underscore function that will convert its + argument to a sensible instance of the target type. For example, if + you have an array of numbers that you want to sort and that may + occasionally contain null or undefined, you can + control whether you want to sort these before or after all numbers + by passing an iteratee to _.sortBy that returns + -Infinity or +Infinity for such values, + respectively. Or maybe you want to treat them as zeros; it is up to + you. The same iteratee can also be passed to other + Underscore functions to ensure that the behavior is consistent. +
  • +
+

+

Change Log

From d11ce386482c876762cec5b406b2e9ce581aaa81 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Thu, 7 May 2020 00:51:12 +0200 Subject: [PATCH 2/3] Shorten the treatise --- index.html | 42 +++--------------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/index.html b/index.html index 29c7ddb09..1d762ea2f 100644 --- a/index.html +++ b/index.html @@ -2435,7 +2435,7 @@

Notes

- On using the < operator in JavaScript + On the use of < in Underscore
Underscore functions that depend on ordering, such as _.sortBy and @@ -2446,47 +2446,11 @@

Notes

important to understand that these operators are only meaningful for numbers and strings. You can throw any value to them, but JavaScript will convert the operands to string or number first before performing - the actual comparison. -

-

- If you use the relational operators naievely and pass an operand that + the actual comparison. If you pass an operand that cannot be meaningfully converted to string or number, it ends up being - NaN by default. This frequently causes confusion because a - comparison with NaN always yields false: -

-
-1 < NaN // false
-NaN < 1 // false
-NaN == 1 // false
-'a' < NaN // false
-NaN < 'a' // false
-NaN == 'a' // false
-NaN < NaN // false
-NaN <= NaN // false!
-NaN === NaN // false!
-      
-

- In the past, people have tried passing such operands to Underscore - functions as well. This invariably led to confusion, too. For example, - consider the following apparent inconsistency between _.sortBy - and _.sortedIndex (reported in - issue #1834): -

-
-_.sortBy([undefined, 1, undefined, 2]);
-// => [1, 2, undefined, undefined]
-_.sortedIndex([1, 2, undefined, undefined], undefined);
-// => 0; reporter expected 2
-      
-

- The problem with this example, however is not that _.sortBy - and _.sortedIndex are inconsistent with each other, but that - unsortable values are being passed into the functions in the first - place. undefined is just one of the many possible values that - is converted to NaN. + NaN by default. This value is unsortable.

- Take home point: make sure that ordering makes sense for your values. Ideally, the values that you are sorting should either be all (meaningfully convertible to) strings or all (meaningfully convertible to) numbers. If this is not the case, you have two options: From bff968b756d1f789f0fc912c6f60056d75c39c8d Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Thu, 7 May 2020 23:37:41 +0200 Subject: [PATCH 3/3] Add a link to iteratee --- index.html | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/index.html b/index.html index 1d762ea2f..53c76fe8c 100644 --- a/index.html +++ b/index.html @@ -2461,16 +2461,17 @@

Notes

  • Pick a target type, i.e., either string or number, and pass an - iteratee to your Underscore function that will convert its - argument to a sensible instance of the target type. For example, if - you have an array of numbers that you want to sort and that may - occasionally contain null or undefined, you can - control whether you want to sort these before or after all numbers - by passing an iteratee to _.sortBy that returns - -Infinity or +Infinity for such values, - respectively. Or maybe you want to treat them as zeros; it is up to - you. The same iteratee can also be passed to other - Underscore functions to ensure that the behavior is consistent. + iteratee to your Underscore + function that will convert its argument to a sensible instance of + the target type. For example, if you have an array of numbers that + you want to sort and that may occasionally contain null or + undefined, you can control whether you want to sort these + before or after all numbers by passing an iteratee to + _.sortBy that returns -Infinity or + +Infinity for such values, respectively. Or maybe you want + to treat them as zeros; it is up to you. The same iteratee + can also be passed to other Underscore functions to ensure that the + behavior is consistent.