sort reorders the array in place and returns the same array. For a copy, use toSorted.
Default order. With no comparator, every element is converted with ToString and the strings are compared by UTF-16 code units. That is why numbers sort as text ([10, 9, 1, 100] becomes [1, 10, 100, 9]) and why 'B' sorts before 'a'.
Comparator. (a, b) => number returns a negative number to put a first, a positive number to put b first, and 0 to treat them as equal. For numbers, a - b ascending and b - a descending is the usual idiom (safe for finite numbers). The spec converts the result with ToNumber, and treats NaN as 0. Returning a boolean (a > b) is wrong: false and true become 0 and 1, and a comparator must be able to say "less than". The result depends on the algorithm, so it's implementation-defined.
Stability. Since ES2019 the spec requires a stable sort: items the comparator calls equal keep their original relative order. That is what makes "sort by last name, then by country" work with two passes.
Consistent comparator. If the comparator is not consistent (same answer for the same pair, transitive, symmetric), the resulting order is implementation-defined. A random comparator like () => Math.random() - 0.5 is therefore not a correct shuffle.
undefined and holes. undefined values are never passed to the comparator. They are moved to the end, followed by holes (the spec collects only existing indices, sorts them, writes them back and deletes the remaining indices). toSorted instead reads holes as undefined.
Text. Use a.localeCompare(b) or an Intl.Collator for human-language order; code-unit order puts 'é' after 'z'.
The algorithm is implementation-defined: the spec fixes the result, not the order of comparator calls.