Рассмотрите следующие данные для тестирования сценария.
Когда я использую метод сортировки массива с функцией сравнения:
['a', 7, 65, '65'].sort((a,b) => a-b)
Вывод для Mozilla:
[ 7, 65, "65", "a" ]
Вывод для Chrome
["a", 7, 65, "65"]
Кажется, вывод в обоих случаях отличается. Пожалуйста, сосредоточьтесь на причине, по которой это происходит, а не на том, как сортировать.
Цель этого вопроса — понять, почему существует разная реализация сортировки при сравнении NaN
в разных движках.
Пример: 'a' - 65
вернет Nan
;
[Обновление]
Сортировка ['a', 65].sort((a,b) => a-b)
Chrome: [65, 'a']
Mozilla: ['a', 65]
Сортировка [65, 'a'].sort((a,b) => a-b)
Chrome: ['a', 65]
Mozilla: [65, 'a']
Почему происходит такое поведение
это интригует
Попробуйте
['a', 7, 65, '65'].sort((a,b) => a - b || a > b)
, чтобы избавиться от неопределенных сравнений строк и целых чисел.@WaisKamal, который вернет неправильный тип данных для компаратора
Похоже, что различия в реализации заключаются в том, как
.sort()
сравнивается сNaN
.@ Фил, я тебя не понял, как он вернет неправильный тип? Если он сравнивает два числа, он возвращает число. Если он сравнивает две строки, он возвращает логическое значение.
Реализация сортировки кажется одинаковой в Chrome и Safari, но отличается в Mozilla. В данном случае это просто сравнение стабильной сортировки номеров юникода.
@WaisKamal компаратор должен возвращать целое число, а не логическое значение. См. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Не знал этого раньше, но в этом случае вы можете просто преобразовать логическое значение в число:
['a', 7, 65, '65'].sort((a,b) => a - b || Number(a > b))
.Это интересно, но ответа/причины мы здесь, скорее всего, не найдем и, наверное, не должны. Как вы говорите, компаратор должен возвращать целое число. Возврат NaN запрашивает UB
NaN
результаты не имеют точно определенного места. Так вы получите неточно определенное место. Не очень большая загадка.@WaisKamal это просто не сработает. Вы получите только
0
или1
из того, в котором отсутствует-1
, чтобы указать, чтоb
предшествуетa
@WaisKamal Сортировка в JavaScript: разве возврата логического значения не должно быть достаточно для функции сравнения?
В чем тут вопрос?
Ребята, вы уходите от сути вопроса. :-D Ищите причину, почему это происходит, а не решение.
@ Фил, неважно, используй
Number(a > b) - 0.5
:)"Ребята, вы уходите от фактического вопроса" это довольно сложно, учитывая, что опубликованный вами вопрос не содержит вопросов. Вы сказали, что есть разница. Есть "PS: не рассматривайте возможность изменения возвращаемого типа в функции.", но я не понимаю, к чему это относится. Ваше последнее обновление заключалось в добавлении ссылки на исходный код C++ для WebKit. В нынешнем виде не спрашивает что-либо конкретное.
@WaisKamal, тогда вы пропустите проверку на равенство (
0
). Просто не делай этого("a"-65) - это NaN, из-за этого и происходит. Некоторые вещи в программировании просто не определены и зависят от реализации, будь то JavaScript, C или другие языки. Если вы нарушите спецификацию функций компаратора, у вас останется это.
@SantoshKumar Chrome и Firefox используют разные интерпретаторы (V8 и Baseline(?) соответственно), и кажется, что каждый из них имеет различную реализацию
Array.sort
.@VLAZ обновил дополнительную информацию об этом. Я добавил код C++, чтобы понять, что происходит под капотом движков на основе webkit. Я ищу причину, по которой сортировка дает разные решения в разных браузерах.
@Phil, если две строки равны, порядок их размещения не имеет значения.
@WaisKamal Но, в конце концов, это стабильный вид, насколько мне известно. Сравните юникод и верните в порядке возрастания. Какой здесь правильный? В чем причина подмены.
@SantoshKumar, какой у тебя вопрос? Вы говорите, что поведение отличается в разных браузерах, и мы сказали вам, что это происходит из-за возвращаемого типа
sort
в вашей реализации.Это происходит из-за того, что Firefox использует SpiderMonkey, а Chrome использует V8 в качестве JS-движка, а поведение NaN во время сортировки неодинаково в разных движках.
@SantoshKumar причина проста - результат
NaN
не указан в спецификациях. Таким образом, вы получаете поведение, которое разные люди считали уместным. Но нет единого мнения о том, что такое «уместно».@AyushGupta Тип возврата сортировки? Как это влияет на сортировку в Mozilla и Chrome?
@SantoshKumar что такое
"a" - 65
@SantoshKumar обратитесь к ссылке, опубликованной VLAZ: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…. "Сравните юникод и верните в порядке возрастания." сделайте это в своей функции сортировки.
относительно вашего редактирования, и, как предложил Аюш: я почти уверен, что Chrome больше не использует JavaScriptCore, а скорее V8, поэтому ссылка на источник, вероятно, не актуальна
@ТобиасК. Да, Safari использует JCore.
Голосование за закрытие вопроса Нужны подробности или ясность, так как этот вопрос не содержит каких-либо конкретных вопросов.
Вот ссылка на соответствующую спецификацию ECMA. И я цитирую Порядок сортировки определяется реализацией [...], если comparefn не является неопределенным и не является последовательной функцией сравнения для элементов items . Спецификация явно разрешает поведение, определяемое реализацией, когда comparefn ведет себя неправильно.
@SantoshKumar Согласно спецификации, поведение оба движка правильное. Причина в том, что вы предоставляете плохую функцию сравнения в качестве аргумента, неясно, каким должно быть ваше желаемое поведение, поэтому вы оставляете движку решать, что они считают правильным.
@hackape Я согласен с тем, что вы говорите. Путаница и вопрос, который у меня есть, заключается в том, что реализация сортировки не должна быть одинаковой? Даже [tc39.es/ecma262/multipage/… говорит, что реализация такого может быть разной. Фактический вопрос заключается в том, почему существуют различия в разных браузерах, поскольку происходит простой механизм сортировки.
@hackape также определена функция сравнения в моем случае. Просто его сортировка происходит по-другому
@SantoshKumar, в каком порядке следует сортировать
["hello", 500, {}]
и почему в соответствии с вашей функцией сравнения?@AyushGupta Я обновил свой вопрос выше. Прочтите еще раз. Это больше о том, почему разные движки имеют разный механизм сортировки. Вам нужно больше разъяснений?
@SantoshKumar Спецификация ES НЕ определяет поведение, когда функция сравнения не возвращает
-1
0
или1
(или любое другое число). В этом случае браузеры могут сортировать по своему усмотрению, и разные браузеры делают это по-разному.@SantoshKumar "почему существуют различия в разных браузерах, так как это простой механизм сортировки, который происходит" это точно потому что это простой механизм сортировки. Это недостаточно для этого случая. Функция сравнения должна возвращать положительный, отрицательный или нулевой результат. Таким образом, он оборудован для работы с положительными, отрицательными или нулевыми значениями.
NaN
не является ни положительным, ни отрицательным, ни нулем. Следовательно, обращение с ним должно стать одним из трех других видов поведения. Мы можем исключить ноль, так что это одно из двух - положительное или отрицательное. Три браузера выбрали разные вещи.почему существует разная реализация сортировки при сравнении NaN в разных движках - потому что спецификация не определяет, каким должно быть поведение
И, честно говоря, хорошо, что в разных браузерах поведение undefined, подобное этому, различно, иначе люди начали бы полагаться на поведение spec-undefined вместо того, чтобы делать это правильно.
@AyushGupta, ВЛАЗ, я понял твою точку зрения. Полностью имеет смысл то, что вы говорите. Я пытался понять, какой алгоритм сортировки работает за array.sort(comparfun). Несколько лет назад большинство браузеров перешли на TimSort, чтобы сделать его более эффективным. Похоже, что сортировка зависит от браузера, когда это NaN.
@AyushGupta как это хорошо? Если нет последовательного способа узнать, что произойдет в каком браузере.
@SantoshKumar да, я именно так и считаю. Итак, теперь пользователи вынуждены обрабатывать NaN в своей логике, возвращая числовое значение для определенного поведения, что и ДОЛЖНО возвращать comparefn в соответствии со спецификацией, тем самым способствуя правильному поведению.
«Я пытался понять, какой алгоритм сортировки работает за array.sort(comparfun)», тогда вы спросили проблема XY. Вопрос о том, как обрабатывается
NaN
, никоим образом не раскрывает алгоритм. На самом деле браузеры обычно используют разные алгоритмы в зависимости от размера входных данных — для очень маленьких массивов они могут использовать пузырьковую сортировку и что-то более сложное для больших массивов. Нет никаких гарантий относительно алгоритма между различными входными данными, браузерами или версиями..sort()
— это просто контракт.