我正在使用anArrayOfObjects.sort((a, b) => a.value - b.value),其中某些物件沒有value屬性。
這導致了 Firefox 和 Chrome 中的不同結果,其中 Chrome 似乎將沒有value屬性/未定義值的物件排序到最后,而 Firefox 沒有。
規范是否沒有規定 Chrome 給出的結果,意味著 Firefox 的結果是錯誤的?還是sort結果的那一部分取決于特定的實作?
const data2 = [
{ 'name' : 'a', 'value' : 5 },
{ 'name' : 'b', 'value' : 2 },
{ 'name' : 'c' },
{ 'name' : 'd', 'value' : 1 }
];
console.log('before sorting: ', data2);
data2.sort((a, b) => a.value - b.value);
console.log('after sorting: ', data2);
uj5u.com熱心網友回復:
兩者都不是“錯誤的”。
undefined - undefined,undefined - 1和1 - undefined所有的回報NaN,和NaN東西相比總是 false。
兩種瀏覽器之間的差異可能是由于排序實作。
使用的排序演算法可以給出不同的結果,這取決于預先值的順序,以及實作如何處理NaN.
uj5u.com熱心網友回復:
不要讓瀏覽器引擎決定如何在有疑問的情況下處理您的代碼,只需撰寫沒有它的代碼:
data2.sort((a, b) => (a?.value || 0) - (b?.value || 0));
(默認值可以是一些小的或大的數字,以便按照您需要的順序進行排序。)
uj5u.com熱心網友回復:
比較函式的作業原理如下:
compareFn(a, b)回傳值 |
排序 |
|---|---|
< 0 |
排序a后b |
> 0 |
a先排序b |
=== 0 |
a保持和的原始順序b |
任何涉及的減法undefined都會給出回傳值NaN,根據規范,它會立即轉換為0。但是,順序將取決于實作使用的特定演算法,因為它決定了以這種方式比較哪些值。
當您注銷比較時,問題變得更加清晰:
const data2 = [
{ 'name' : 'a', 'value' : 5 },
{ 'name' : 'b', 'value' : 2 },
{ 'name' : 'c' },
{ 'name' : 'd', 'value' : 1 }
];
console.log('before sorting: ', data2);
data2.sort((a, b) => (console.log(a.value, b.value), a.value - b.value));
console.log('after sorting: ', data2);
Firefox似乎在問
> 0:5 2 5 undefined undefined 1ais'a'和bis'b',回傳值是3so'a'is 必須是 after'b'。ais'a'和bis'c',回傳值 is0so'a'停留在之前'c'。ais'c'和bis'd',回傳值 is0so'c'停留在之前'd'。
Chrome似乎在問
< 0:2 5 undefined 2 undefined 5 1 5 1 2ais'b'和bis'a',回傳值 is-3so'b'必須在之前'a'。ais'c'和bis'b',回傳值 is0so'c'停留在之后'b'ais'c'和bis'a',回傳值 is0so'c'停留在之后'a'ais'd'和bis'a',回傳值 is-4so'd'必須在之前'a'ais'd'和bis'b',回傳值 is-1so'd'必須在之前'b'
特別是 Chrome 從來沒有直接比較'c','d'所以從來沒有被告知要讓它們保持相同的順序。
uj5u.com熱心網友回復:
眾所周知,排序演算法是特定于瀏覽器實作的,此外,由于沒有銀彈??演算法,某個瀏覽器可能會針對不同的資料形狀使用不同的排序演算法作為優化技術。
在 Firefox 中查看以下示例結果時,這一點變得很明顯:
const arr1 = [
{ 'value' : 5 },
{ 'value' : 2 },
{ 'value': undefined },
{ 'value' : 4 },
{ 'value' : 3 },
{ 'value': undefined },
{ 'value' : 1 },
{ 'value' : 0 }
];
const arr2 = [5, 2, undefined, 4, 3, undefined, 1, 0];
arr1.sort((a, b) => a.value - b.value);
arr2.sort((a, b) => a - b);
console.log(arr1.map(v => `${v.value}`).join());
console.log(arr2.map(v => `${v}`).join());
事實上,上述示例的 Chrome 結果符合規范:
- 讓 SortCompare 成為一個新的抽象閉包,帶有引數 (x, y),它捕獲 comparefn 并在呼叫時執行以下步驟
:如果 x 和 y 都未定義,則回傳 0??。
灣。如果 x 未定義,則回傳 1??。
C。如果 y 未定義,則回傳 -1??。
從上面的陳述可以得出結論,undefined值總是比較大于任何其他值,這就是它們最后排序的原因。
這個結果可以通過merge sort對未定義值進行特殊處理的演算法來實作,下面是它的偽代碼:
const mergeSort = arr => {
let voids = 0;
const merge = (l, r) => {
const out = [];
l.length && l[0] === undefined && (l.shift(), voids );
while (l.length && r.length) out.push(l[0] <= r[0] ? l.shift() : r.shift());
while(l.length) out.push(l.shift());
while(r.length) out.push(r.shift());
return out;
};
const sort = arr => {
if (arr.length < 2)
return arr;
const m = Math.floor(arr.length / 2);
const l = arr.slice(0, m), r = arr.slice(m);
return merge(sort(l), sort(r));
};
const result = sort(arr);
while (voids--) result.push(undefined);
return result;
};
const arr = [5, 2, undefined, 4, 3, undefined, 1, 0];
console.log(mergeSort(arr).map(v => `${v}`).join());
關于Firefox 中的物件陣列排序結果,在第一個例子中,可以通過一個簡單的insertion sort演算法得到,如下所示:
const insertionSort = arr => {
for (let i = 1; i < arr.length; i ) {
let x = i - 1, n = arr[i];
for (; x >= 0 && arr[x] > n; x--)
arr[x 1] = arr[x];
arr[x 1] = n;
}
return arr;
};
const arr = [5, 2, undefined, 4, 3, undefined, 1, 0];
console.log(insertionSort(arr).map(v => `${v}`).join());
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/512348.html
