JavaScript ma wiele dobrych i złych części, o których często nie wiemy lub nawet korzystamy z nich nieświadomie. Ostatnio przy rozwiązywaniu zadań Codility trafiłem kilka kwestii, które zaskoczyły całkowicie w swoim zachowaniu.
Sortowanie tablicy
Ustawienie elementów tablicy według określonego porządku to bardzo powszechna czynność w programowaniu. Wykonanie tej czynności wymaga jedynie wywołania funkcji sort()
dla tablicy, jednak diabeł tkwi w szczegółach.
Chyba najbardziej naturalne i najczęstsze jest sortowanie w porządku rosnącym. Zatem spróbujmy tego w przypadku tablicy z liczbami.
// only positive numbers
numbers = [3, 1, 4, 2];
numbers.sort();
// [1, 2, 3, 4]
Sortowanie tablicy z dodatnimi liczbami działa dokładnie tak, jakbyśmy tego oczekiwali, ale to tylko przypadek. Problem pojawia się, gdy nasza tablica zawiera liczby ujemne lub dwucyfrowe:
// positive and negative numbers
numbers = [-3, -1, -4, -2, 13, 1, 4, 2, 0];
numbers.sort();
// [-1, -2, -3, -4, 0, 1, 13, 2, 4]
Przyczyna takiego zachowania to sposób w jaki funkcja sort()
określa kolejność, a mianowicie poprzez kod znaku Unicode danego elementu tablicy, mówiąc inaczej sortuje te elementy jakby były słowami.
Jedynym rozwiązaniem jest przekazanie odpowiedniej funkcji sortującej w argumencie.
function compareNumbers(a, b) {
return a - b;
}
// positive and negative numbers
numbers = [-3, -1, -4, -2, 13, 1, 4, 2, 0];
numbers.sort(compareNumbers);
// [-4, -3, -2, -1, 0, 1, 2, 3, 4]
Konwersja liczby całkowitej do postaci binarnej
Niekiedy potrzebujemy wartości zmienny w innej postaci, choćby dwójkowej lub odwrotnie. Wówczas przydatna jest znajomość w jaki sposób jeden zapis odpowiada innemu. Bardziej złożone operacje bitowe, dzielenie modulo czy przesuwanie bitów są wtedy niezbędne przy konwersji. Tutaj JavaScript zaskakuje pozytywnie, bo funkcja toString()
dla obiektu Number dokonuje takich konwersji.
Omawiana kwestia wymaga podania opcjonalnego argumentu, który określa wykładnik wyliczeń. Domyślnie jest to wartość 10
, zatem liczby są wyświetlane w postaci dziesiętnej jako ciąg znaków.
(16).toString(); // 16
(16).toString(2); // 10000
Taka konwersja jest możliwa w obie strony. Przykładowo 16
w postaci dziesiętnej to 20
w systemie ósemkowym. Analogicznie możemy odwrócić sytuację ósemkowe 20
wyświetlić jako 16
w systemie dzisiętnym lub 10000
w systemie binarnym.
(16).toString(8); // 20
(020).toString(10); // 16
(020).toString(2); // 10000
Należy zapamiętać, że wykładnik wyliczeń jaki przyjmuje funkcja toString()
to liczba od 2 do 36, zatem możliwości jest wiele.