Javascript: сортировка массива возвращает разные результаты для Chrome и Firefox [закрыто]

avatar
Santosh Kumar
9 августа 2021 в 06:21
277
0
3

Рассмотрите следующие данные для тестирования сценария.

Когда я использую метод сортировки массива с функцией сравнения:

['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']

Почему происходит такое поведение

Источник
decpk
9 августа 2021 в 06:26
3

это интригует

Wais Kamal
9 августа 2021 в 06:29
0

Попробуйте ['a', 7, 65, '65'].sort((a,b) => a - b || a > b), чтобы избавиться от неопределенных сравнений строк и целых чисел.

Phil
9 августа 2021 в 06:30
0

@WaisKamal, который вернет неправильный тип данных для компаратора

Phil
9 августа 2021 в 06:31
1

Похоже, что различия в реализации заключаются в том, как .sort() сравнивается с NaN.

Wais Kamal
9 августа 2021 в 06:35
0

@ Фил, я тебя не понял, как он вернет неправильный тип? Если он сравнивает два числа, он возвращает число. Если он сравнивает две строки, он возвращает логическое значение.

Santosh Kumar
9 августа 2021 в 06:36
0

Реализация сортировки кажется одинаковой в Chrome и Safari, но отличается в Mozilla. В данном случае это просто сравнение стабильной сортировки номеров юникода.

Phil
9 августа 2021 в 06:36
1

@WaisKamal компаратор должен возвращать целое число, а не логическое значение. См. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

Wais Kamal
9 августа 2021 в 06:38
0

Не знал этого раньше, но в этом случае вы можете просто преобразовать логическое значение в число: ['a', 7, 65, '65'].sort((a,b) => a - b || Number(a > b)).

Tobias K.
9 августа 2021 в 06:38
1

Это интересно, но ответа/причины мы здесь, скорее всего, не найдем и, наверное, не должны. Как вы говорите, компаратор должен возвращать целое число. Возврат NaN запрашивает UB

VLAZ
9 августа 2021 в 06:38
3

NaN результаты не имеют точно определенного места. Так вы получите неточно определенное место. Не очень большая загадка.

Phil
9 августа 2021 в 06:39
0

@WaisKamal это просто не сработает. Вы получите только 0 или 1 из того, в котором отсутствует -1, чтобы указать, что b предшествует a

VLAZ
9 августа 2021 в 06:49
2

В чем тут вопрос?

Santosh Kumar
9 августа 2021 в 06:50
0

Ребята, вы уходите от сути вопроса. :-D Ищите причину, почему это происходит, а не решение.

Wais Kamal
9 августа 2021 в 06:53
0

@ Фил, неважно, используй Number(a > b) - 0.5 :)

VLAZ
9 августа 2021 в 06:54
3

"Ребята, вы уходите от фактического вопроса" это довольно сложно, учитывая, что опубликованный вами вопрос не содержит вопросов. Вы сказали, что есть разница. Есть "PS: не рассматривайте возможность изменения возвращаемого типа в функции.", но я не понимаю, к чему это относится. Ваше последнее обновление заключалось в добавлении ссылки на исходный код C++ для WebKit. В нынешнем виде не спрашивает что-либо конкретное.

Phil
9 августа 2021 в 06:54
0

@WaisKamal, тогда вы пропустите проверку на равенство (0). Просто не делай этого

Tobias K.
9 августа 2021 в 06:55
2

("a"-65) - это NaN, из-за этого и происходит. Некоторые вещи в программировании просто не определены и зависят от реализации, будь то JavaScript, C или другие языки. Если вы нарушите спецификацию функций компаратора, у вас останется это.

Wais Kamal
9 августа 2021 в 06:56
0

@SantoshKumar Chrome и Firefox используют разные интерпретаторы (V8 и Baseline(?) соответственно), и кажется, что каждый из них имеет различную реализацию Array.sort.

Santosh Kumar
9 августа 2021 в 06:57
0

@VLAZ обновил дополнительную информацию об этом. Я добавил код C++, чтобы понять, что происходит под капотом движков на основе webkit. Я ищу причину, по которой сортировка дает разные решения в разных браузерах.

Wais Kamal
9 августа 2021 в 06:57
0

@Phil, если две строки равны, порядок их размещения не имеет значения.

Santosh Kumar
9 августа 2021 в 06:59
1

@WaisKamal Но, в конце концов, это стабильный вид, насколько мне известно. Сравните юникод и верните в порядке возрастания. Какой здесь правильный? В чем причина подмены.

Ayush Gupta
9 августа 2021 в 06:59
1

@SantoshKumar, какой у тебя вопрос? Вы говорите, что поведение отличается в разных браузерах, и мы сказали вам, что это происходит из-за возвращаемого типа sort в вашей реализации.

Ayush Gupta
9 августа 2021 в 07:00
2

Это происходит из-за того, что Firefox использует SpiderMonkey, а Chrome использует V8 в качестве JS-движка, а поведение NaN во время сортировки неодинаково в разных движках.

VLAZ
9 августа 2021 в 07:00
1

@SantoshKumar причина проста - результат NaN не указан в спецификациях. Таким образом, вы получаете поведение, которое разные люди считали уместным. Но нет единого мнения о том, что такое «уместно».

Santosh Kumar
9 августа 2021 в 07:01
0

@AyushGupta Тип возврата сортировки? Как это влияет на сортировку в Mozilla и Chrome?

Ayush Gupta
9 августа 2021 в 07:01
0

@SantoshKumar что такое "a" - 65

Wais Kamal
9 августа 2021 в 07:02
0

@SantoshKumar обратитесь к ссылке, опубликованной VLAZ: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…. "Сравните юникод и верните в порядке возрастания." сделайте это в своей функции сортировки.

Tobias K.
9 августа 2021 в 07:02
0

относительно вашего редактирования, и, как предложил Аюш: я почти уверен, что Chrome больше не использует JavaScriptCore, а скорее V8, поэтому ссылка на источник, вероятно, не актуальна

Ayush Gupta
9 августа 2021 в 07:04
0

@ТобиасК. Да, Safari использует JCore.

Ayush Gupta
9 августа 2021 в 07:07
0

Голосование за закрытие вопроса Нужны подробности или ясность, так как этот вопрос не содержит каких-либо конкретных вопросов.

hackape
9 августа 2021 в 07:08
0

Вот ссылка на соответствующую спецификацию ECMA. И я цитирую Порядок сортировки определяется реализацией [...], если comparefn не является неопределенным и не является последовательной функцией сравнения для элементов items . Спецификация явно разрешает поведение, определяемое реализацией, когда comparefn ведет себя неправильно.

hackape
9 августа 2021 в 07:12
1

@SantoshKumar Согласно спецификации, поведение оба движка правильное. Причина в том, что вы предоставляете плохую функцию сравнения в качестве аргумента, неясно, каким должно быть ваше желаемое поведение, поэтому вы оставляете движку решать, что они считают правильным.

Santosh Kumar
9 августа 2021 в 07:31
0

@hackape Я согласен с тем, что вы говорите. Путаница и вопрос, который у меня есть, заключается в том, что реализация сортировки не должна быть одинаковой? Даже [tc39.es/ecma262/multipage/… говорит, что реализация такого может быть разной. Фактический вопрос заключается в том, почему существуют различия в разных браузерах, поскольку происходит простой механизм сортировки.

Santosh Kumar
9 августа 2021 в 07:34
0

@hackape также определена функция сравнения в моем случае. Просто его сортировка происходит по-другому

Ayush Gupta
9 августа 2021 в 07:43
3

@SantoshKumar, в каком порядке следует сортировать ["hello", 500, {}] и почему в соответствии с вашей функцией сравнения?

Santosh Kumar
9 августа 2021 в 07:48
0

@AyushGupta Я обновил свой вопрос выше. Прочтите еще раз. Это больше о том, почему разные движки имеют разный механизм сортировки. Вам нужно больше разъяснений?

Ayush Gupta
9 августа 2021 в 07:49
0

@SantoshKumar Спецификация ES НЕ определяет поведение, когда функция сравнения не возвращает -1 0 или 1 (или любое другое число). В этом случае браузеры могут сортировать по своему усмотрению, и разные браузеры делают это по-разному.

VLAZ
9 августа 2021 в 07:51
2

@SantoshKumar "почему существуют различия в разных браузерах, так как это простой механизм сортировки, который происходит" это точно потому что это простой механизм сортировки. Это недостаточно для этого случая. Функция сравнения должна возвращать положительный, отрицательный или нулевой результат. Таким образом, он оборудован для работы с положительными, отрицательными или нулевыми значениями. NaN не является ни положительным, ни отрицательным, ни нулем. Следовательно, обращение с ним должно стать одним из трех других видов поведения. Мы можем исключить ноль, так что это одно из двух - положительное или отрицательное. Три браузера выбрали разные вещи.

Ayush Gupta
9 августа 2021 в 07:51
1

почему существует разная реализация сортировки при сравнении NaN в разных движках - потому что спецификация не определяет, каким должно быть поведение

Ayush Gupta
9 августа 2021 в 07:54
1

И, честно говоря, хорошо, что в разных браузерах поведение undefined, подобное этому, различно, иначе люди начали бы полагаться на поведение spec-undefined вместо того, чтобы делать это правильно.

Santosh Kumar
9 августа 2021 в 07:55
0

@AyushGupta, ВЛАЗ, я понял твою точку зрения. Полностью имеет смысл то, что вы говорите. Я пытался понять, какой алгоритм сортировки работает за array.sort(comparfun). Несколько лет назад большинство браузеров перешли на TimSort, чтобы сделать его более эффективным. Похоже, что сортировка зависит от браузера, когда это NaN.

Santosh Kumar
9 августа 2021 в 07:56
0

@AyushGupta как это хорошо? Если нет последовательного способа узнать, что произойдет в каком браузере.

Ayush Gupta
9 августа 2021 в 07:58
3

@SantoshKumar да, я именно так и считаю. Итак, теперь пользователи вынуждены обрабатывать NaN в своей логике, возвращая числовое значение для определенного поведения, что и ДОЛЖНО возвращать comparefn в соответствии со спецификацией, тем самым способствуя правильному поведению.

VLAZ
9 августа 2021 в 08:41
2

«Я пытался понять, какой алгоритм сортировки работает за array.sort(comparfun)», тогда вы спросили проблема XY. Вопрос о том, как обрабатывается NaN, никоим образом не раскрывает алгоритм. На самом деле браузеры обычно используют разные алгоритмы в зависимости от размера входных данных — для очень маленьких массивов они могут использовать пузырьковую сортировку и что-то более сложное для больших массивов. Нет никаких гарантий относительно алгоритма между различными входными данными, браузерами или версиями. .sort() — это просто контракт.

Ответы (0)