diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 3efe5c409b..a257a2547d 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -265,10 +265,9 @@ function ArrayToSorted(comparefn) { var len = ToLength(O.length); var items = new List(); - var itemsLen = 0; + var itemsLen = len; for (var k = 0; k < len; k++) { - if (k in O) - items[itemsLen++] = O[k]; + items[k] = O[k]; } var wrappedCompareFn = comparefn; @@ -303,9 +302,7 @@ function ArrayToSorted(comparefn) { if (itemsLen > 1) MergeSort(items, itemsLen, sortCompare); - var A = ArraySpeciesCreate(O, 0); - A.length = len; - + var A = ArraySpeciesCreate(O, len); for (var j = 0; j < itemsLen; j++) _DefineDataProperty(A, j, items[j]); diff --git a/js/src/tests/ecma_6/Array/toSorted.html b/js/src/tests/ecma_6/Array/toSorted.html new file mode 100644 index 0000000000..3738b05c48 --- /dev/null +++ b/js/src/tests/ecma_6/Array/toSorted.html @@ -0,0 +1,59 @@ + + +Array.prototype.toSorted test + +

+
+
diff --git a/js/src/tests/ecma_6/Array/toSorted.js b/js/src/tests/ecma_6/Array/toSorted.js
new file mode 100644
index 0000000000..fbd2540deb
--- /dev/null
+++ b/js/src/tests/ecma_6/Array/toSorted.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+assertEq(typeof Array.prototype.toSorted, "function");
+
+// Non-mutating behavior.
+let original = [3, 1, 2];
+let sorted = original.toSorted();
+assertEq(original !== sorted, true);
+assertEq(original.join(","), "3,1,2");
+assertEq(sorted.join(","), "1,2,3");
+
+// Compare function.
+let nums = [10, 1, 5];
+let desc = nums.toSorted((a, b) => b - a);
+assertEq(desc.join(","), "10,5,1");
+
+// Stable sort.
+let stableInput = [
+    {v: 1, id: "a"},
+    {v: 1, id: "b"},
+    {v: 1, id: "c"}
+];
+let stableSorted = stableInput.toSorted((x, y) => x.v - y.v);
+assertEq(stableSorted.map(o => o.id).join(""), "abc");
+
+// Holes are treated as undefined (properties are created).
+let sparse = [3, , 1];
+let sparseSorted = sparse.toSorted();
+assertEq(sparseSorted.length, 3);
+assertEq(sparseSorted[0], 1);
+assertEq(sparseSorted[1], 3);
+assertEq(2 in sparseSorted, true);
+assertEq(sparseSorted[2], undefined);
+
+// Array-like input.
+let arrayLike = {0: 2, 1: 1, length: 2};
+let arrayLikeSorted = Array.prototype.toSorted.call(arrayLike);
+assertEq(Array.isArray(arrayLikeSorted), true);
+assertEq(arrayLikeSorted.join(","), "1,2");
+
+// Getter access order (ascending indices).
+let accessLog = [];
+let getterArr = {
+    length: 3,
+    get 0() { accessLog.push(0); return 3; },
+    get 1() { accessLog.push(1); return 1; },
+    get 2() { accessLog.push(2); return 2; }
+};
+Array.prototype.toSorted.call(getterArr);
+assertEq(accessLog.join(","), "0,1,2");
+
+// Comparator errors propagate.
+assertThrowsInstanceOf(() => [1, 2].toSorted(1), TypeError);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);