[英]Firefox Array.prototype.sort - is this behaviour correct?
[英]AngularJS orderBy - crazy Array.prototype.sort behaviour in Chromium browsers - Cannot clear sort
在我的一個項目中,有些事使我發瘋。
我有一些與此非常相似的代碼(我嘗試使其與我的盡可能相似,包括我使用的所有JS文件,等等,但是正如您所見,此Plnkr中的代碼似乎並不重要,因為我無法在此處復制它...): http : //plnkr.co/edit/SCUCsxLgu2zFzMhZ0whs?p=preview
我的問題是,當我設置predicate=''
,排序沒有100%清除。 Angular似乎改變了我的元素順序(此圖片帶有predicate=''
):
當我刪除orderBy
,一切都按其順序排列(就像它是從我的存儲庫中存儲的一樣)。 在使用orderBy
嘗試了數百萬種不同的東西之后,我無法完全弄清排序。
我發現這個案例與我的案例有一些相似之處: Chrome中的AngularJS ngRepeat orderBy ,但事實證明我的案例與該問題無關。
我是一個有耐心的人,所以我進入了angular.js
文件(AngularJS v1.3.15)並開始調試。 這是最關鍵的行:
return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
直到slice.call(array)
排列良好。 執行sort
時,結果是錯誤的。 所以我這樣做:
function comparator(o1, o2) {
for (var i = 0; i < sortPredicate.length; i++) {
var comp = sortPredicate[i](o1, o2);
if (comp !== 0){
console.log(7); // <---------------------
return comp;
}
}
console.log(0); // <---------------------
return 0;
}
function reverseComparator(comp, descending) {
return descending
? function(a, b) {return comp(b,a);}
: comp;
}
猜猜是什么:當predicate=''
為零時,我在控制台中得到的所有內容。 另外,輸入:
slice.call(array).sort
...的回報:
function sort() { [native code] }
因此,我不知道為什么要進行這種排序。 看來,這僅發生在基於Chromium的瀏覽器中(我嘗試過Chrome和Opera)。 FF和IE11按預期清除了排序。
現在,我認為這是一個Chromium錯誤,但是我仍然沒有設法在那個Plnkr中重現它,我想知道為什么(也許數據有些不同?)...
我也嘗試過禁用Chrome擴展程序,但這似乎也沒有什么不同。
鉻和Angular現已聞名。 有人之前注意到過嗎?
有人知道這是怎么回事嗎?
更新:
好。 我想我已經通過在數組中添加更多項來重現它。 看到這里: http : //plnkr.co/edit/SCUCsxLgu2zFzMhZ0whs?p=preview
(聚會時間!:D)
我要去報告給Angular團隊。 他們是Google。 他們也可能會修復Chromium。 :d
排序不一定是穩定的(也就是說,比較相等的元素不一定保持其原始順序)。
因此,這不是瀏覽器中的錯誤。
Angular代碼確實考慮了一個空謂詞:
if (predicate === '') {
// Effectively no predicate was passed so we compare identity
return reverseComparator(compare, descending);
}
具有compare
功能
function compare(v1, v2) {
var t1 = typeof v1;
var t2 = typeof v2;
if (t1 === t2 && t1 === "object") {
v1 = objectToString(v1);
v2 = objectToString(v2);
}
...
和objectToString
被
function objectToString(value) {
if (value === null) return 'null';
if (typeof value.valueOf === 'function') {
value = value.valueOf();
if (isPrimitive(value)) return value;
}
if (typeof value.toString === 'function') {
value = value.toString();
if (isPrimitive(value)) return value;
}
return '';
}
由於您的對象都沒有自己的 valueOf
方法或toString
方法,因此它們最終是相等的(該函數可能會返回"[object Object]"
)。 這使我們回到了ECMAScript規范。
我最終將采用的解決方案是使用以下自定義過濾器:
(function () {
function isNullOrEmpty(str) {
return str === '' || str === undefined || str === null;
}
angular.module('CustomFilters', [])
.filter('okOrderBy', ['$filter', function ($filter) {
return function (array, predicate, reverse) {
if (isNullOrEmpty(predicate)) return array;
return $filter('orderBy')(array, predicate, reverse);
};
}
])
.filter('arrayOrderBy', [function () {
function Comparator(predicate, reverse) {
return reverse ? function (a, b) {
a = a[predicate];
b = b[predicate];
if (a === b) return 0;
return a < b ? 1 : -1;
} : function (a, b) {
a = a[predicate];
b = b[predicate];
if (a === b) return 0;
return a < b ? -1 : 1;
};
}
return function (array, predicate, reverse) {
if (isNullOrEmpty(predicate)) return array;
return array.slice(0).sort(new Comparator(predicate, reverse));
};
}
]);
})();
第二個獨立於Angular濾鏡,我更喜歡它。
但是它僅適用於對象數組,其謂詞僅是屬性名稱,並且不允許“多列”排序。 雖然第一個應該對所有東西都起作用(我想)。
我在應該接受的答案上有一個很大的難題,因為所有其他答案都是有益和有趣的。 我希望我可以不勝感激地投票給他們一次以上。 我正在考慮選擇此答案(我知道...我很自私...),只是因為它解決了問題,並且比用戶“ YOU”提供的答案使用時間短。
另一種方法。 不需要時不要運行排序。
高興的角度讓您可以在此處編寫任何內容。
<tr ng-repeat="friend in (predicate ? (friends | orderBy:predicate:reverse) : friends)">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
</tr>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.