MooTools 1.2 - obiekty natywne - tekst i liczby
15 lutego, 2008
Operacje na ciągach znaków i liczbach to dość często spotykane zadania, zwłaszcza podczas walidacji danych czy przeprowadzania wewnętrznych obliczeń przez skrypt. W MooTools zaimplementowano kilka ciekawych rozszerzeń dla natywnych obiektów String i Number, które z pewnością ułatwią wiele z nich.
Obiekt String
Zaczniemy od omówienia obiektu natywnego String służącego do operowania na ciągach znaków. Dwie metody tego obiektu już mieliśmy okazję poznać przy omawianiu obiektu Array - chodzi o metody hexToRgb i rgbToHex - jak pamiętamy zapis:
["10","AA","FF"].hexToRgb();
Używał metody hexToRgb zawartej w obiekcie Array, ale już zapis postaci:
"10AAFF".hexToRgb();
Używa tej samej metody, ale zawartej w obiekcie String.
W wypadku metody rgbToHex stosujemy zapis postaci:
"rgb(10,20,30)".rgbToHex();
lub:
"rgba(10,20,30,0)".rgbToHex();
Pierwszy zapis to kolor w formacie RGB, a drugi to kolor w formacie RGBA (czyli RGB + kanał alpha). W naszym wypadku ponieważ alpha równa jest 0, zostanie zwrócona wartość transparent.
Oczywiście obie metody podobnie jak w wypadku metod obiektu Array przyjmują jako argument wartość logiczną określającą czy chcemy aby wynik był zwrócony w postaci tablicy czy nie.
Skoro już obracamy się w temacie metod konwertujących to zajmijmy się teraz metodami toInt i toFloat - są to odpowiedniki natywnych parseInt i parseFloat, które służą do zamienienia ciągu znaków na liczbę.
Metody te będziemy zapewne często wykorzystywać przy pobieraniu szerokości elementów do różnego rodzaju obliczeń:
"100px".toInt();
Powyższy zapis zwróci nam po prostu liczbę 100. Podobnie jest z toFloat:
"10.25em".toFloat();
Zwróci nam liczbę zmiennoprzecinkową 10.25 .
Warto jeszcze zwrócić uwagę na to, że metoda toInt może pobierać podstawę systemu w jakim zapisana jest liczba i zamieniać rezultat na liczbę w zapisie dziesiętnym. Przykładowo jeżeli mamy liczbę w zapisie binarnym:
"1111".toInt(2);
Powyższy kod zwróci nam liczbę 15, bo jej reprezentacja w systemie dwójkowym to właśnie 1111.
Myślę, że w wypadku tych metod więcej tłumaczyć nie trzeba, bo tak jak wspominałem to po prostu natywne metody pod innymi nazwami. Oczywiście osoby optymalizujące co popadnie powiedzą, że to nie ma sensu, bo zwykłe parseInt() zadziała tak samo, a różnica jest tylko w zapisie - oczywiście mają rację, ale nikt im metody parseInt używać nie zabrania ;)
Czasami mamy ciągi znaków zawierające skrypty - dzięki metodzie stripScripts możemy usunąć kod JS z ciągu znaków lub wykonać tenże kod i otrzymać ciąg znaków bez kodu JS. Oczywiście przykłady wyjaśnią tutaj wszystko najlepiej:
"<script>alert("To jest test...")</script>Tekst bez kodu JS".stripScripts();
W powyższym wypadku zostanie zwrócony ciąg znaków:
Tekst bez kodu JS
Gdybyśmy jednak jako argument metody stripScripts podali wartość true:
"<script>alert("To jest test...")</script>Tekst bez kodu JS".stripScripts(true);
To pojawiłby się alert z tekstem "To jest test..." i dodatkowo zostałby zwrócony przez tą metodę ciąg znaków taki jak w poprzednim przykładzie.
Z zupełnie nowych metod warto jeszcze wspomnieć metodę substitute (choć w wersji MooTools 1.2 beta 2 jej jeszcze nie było), która ma podobne działanie jak napisana przeze mnie kiedyś klasa Template. Składnia tej metody wygląda następująco:
tekst.substitute(obiekt, ograniczniki);
Drugi argument jest opcjonalny - jest to tablica znaków, które ograniczają tekst do podmienienia. Podmiana następuje na bazie właściwości obiektu. Przykładowo:
"To jest {test}".({test:"testowy tekst"});
Gdybyśmy chcieli podmieniać teksty postaci: <?text?> to zapiszemy:
"To jest <?test?>".({test:"testowy tekst"},["<?","?>"]);
Metoda ta może być bardzo przydatna gdy mamy jakieś szablony tekstu, gdzie zmieniają się tylko określone parametry - nie musimy wtedy generować długich kombinacji ciąg znaków - zmienna - ciąg znaków - zmienna - itd.
Jeżeli chcielibyśmy trochę "posprzątać" w naszym ciągu znaków to mamy do dyspozycji dwie metody - trim i clean, pierwsza z nich usuwa wszystkie spacje z początku i końca ciągu znaków, a druga usuwa wielokrotnie powtórzone znaki spacji, zamieniając je na pojedyncze...
" Tekst testowy ".trim();
Powyższy kod zwróci nam:
Tekst testowy
natomiast kod:
"Test usuwania spacji".clean();
zwróci nam:
Test usuwania spacji
Obiekt String udostępnia nam w MooTools trzy metody do zmiany zapisu ciągu znaków - camelCase, hyphenate i capitalize.
Metoda camelCase zamienia ciągi postaci:
"Tekst-testowy-dla-metody-camelCase"
w tekst postaci:
"TekstTestowyDlaMetodyCamelCase"
Aby uzyskać takie rezultaty należy zapisać:
"Tekst-testowy-dla-metody-camelCase".camelCase();
Tekst jaki zostanie zwrócony przez tą metodę można też zamienić na początkowy poprzez zapis:
"TekstTestowyDlaMetodyCamelCase".hyphenate();
Jak więc widzimy metody camelCase i hyphenate są wzajemnie powiązane...
Metoda capitalize powoduje zamianę pierwszych liter wyrazów na duże litery:
"kolejny testowy tekst".capitalize();
Powyższy kod zwróci nam tekst postaci:
Kolejny Testowy Tekst
Jak widać nic skomplikowanego w tym wszystkim nie ma - ot proste metody do manipulowania ciągami znaków. Pozostały nam jeszcze metody związane z wyrażeniami regularnymi.
Każdy kto zetknął się kiedyś z wyrażeniami regularnymi wie, że czasami istnieje potrzeba znalezienia tekstu zawierającego znaki specjalne stosowane w wyrażeniach regularnych - aby zautomatyzować procedurę ich "neutralizowania" poprzez dodania przez każdym takim znakiem znaku backslash stworzono metodę escapeRegExp:
"Tekst.dla.metody{escapeRegExp}".escapeRegExp();
Powyższy kod zwróci nam tekst:
Tekst\.dla\.metody\{escapeRegExp\}
Metoda ta jest niezwykle przydatna wtedy gdy tekst, który umieszczamy w wyrażeniu regularnym jest generowany dynamicznie.
Wiemy jak "oczyścić" nasz tekst ze znaków specjalnych, a gdzie użyć wyrażeń regularnych ? Chociażby w metodzie test, która sprawdza podany ciąg znaków ze wzorcem podanym jako argument (oczywiście w postaci wyrażenia regularnego).
Jako drugi argument metoda test przyjmuje flagi wyrażenia regularnego takie jak i czy m:
"Kolejny test".test("test");
Powyższy kod zwróci nam wartość logiczną true, ponieważ dany tekst zgadza się z podanym wzorcem. Natomiast w sytuacji:
"Kolejny test".test("TEst");
Otrzymamy wartość logiczną false chyba, że ustawimy flagę ignorowania wielkości znaków:
"Kolejny test".test("TEst","i");
W tym wypadku zwrócona zostanie nam wartość true.
Metoda test jest idealna do walidacji formularzy - pola takie jak adres e-mail, adres strony WWW to typowe miejsca gdzie podczas walidacji korzysta się z wyrażeń regularnych.
Ostatnia metoda obiektu String to contains, która sprawdza czy w określonym ciągu znaków gdzie poszczególne elementy są oddzielone określonym separatorem występuje dany element.
Metoda ta pobiera jako argumenty szukany element i separator:
"a b c d e f g h".contains("i"," ");
Powyższy kod zwróci nam wartość false bo literki i nie ma w naszym ciągu znaków rozdzielanych spacjami, ale już kod:
"ab|cd|ef|gh".contains("gh","|");
Zwróci nam wartość true, bo element gh w tym ciągu rozdzielonym znakami "|" występuje.
Metoda ta jest przydatna zwłaszcza w wypadku miłośników PHP-owskich funkcji explode i implode ;)
Przejdźmy teraz do obiektu Number, który operuje na liczbach...
Obiekt Number
W obiekcie tym znajdziemy dwie takie same metody jak w wypadku obiektu String - toInt i toFloat, ktoś powie, że to bez sensu - zamieniać liczbę na liczbę, jeszcze w wypadku metody toInt można ją wykorzystać do zaokrąglania liczby:
(1234.5).toInt();
Powyższy kod zwróci liczbę 1234. Ale jaki jest sens istnienia toFloat ? Tłumaczyć można to różnie, a ja zostanę przy wersji, która mówi iż pozwala to nam na uniknięcie błędów JS w pewnych sytuacjach - przykładowo pobieramy jakąś wartość i nie wiemy czy jest to liczba czy ciąg znaków, a chcemy uzyskać liczbę - wykonujemy wtedy konwersję tej zmiennej:
zmienna.toInt();
I mamy stuprocentową pewność, że uzyskamy liczbę, a nie błąd w konsoli błędów ;) Oczywiście możnaby sprawdzać czy zmienna jest liczbą funkcją $type, ale powiedzmy sobie szczerze - który zapis lepszy ?
zmienna.toInt();
czy:
if($type(zmienna) != "number") zmienna.toInt();
?
Dla niezorientowanych śpieszę z odpowiedzią iż pierwszy zapis jest lepszy nie tylko z tego powodu, że jest krótszy, ale też wydajniejszy - w drugim wypadku wykona się najpierw funkcja $type (swoją drogą w stosunku do metody toInt jest ona naprawdę rozbudowana), a dopiero potem metoda toInt (jeżeli zmienna jest liczbą). Także jak widać korzyści dodania tych kilku linijek do obiektu natywnego Number są dość wymierne.
Jeszcze apropo zapisu - obiekt Number posiada metodę times (jej drugie imię to each), która powoduje wykonanie danej funkcji określoną ilość razy (jak w pętli for):
(5).times(function(i){alert(i*i);});
Powyższy kod spowoduje wyświetlenie w alertach kwadratów liczb od 0 do 4. Warto jeszcze dodać, że jako drugi argument metoda ta przyjmuje uchwyt dla operatora this (znanego nam skądinąd dzięki metodzie bind obiektu Function). Oczywiście jak wspominałem drugie imię metody times to each:
(5).each(function(i){alert(i*i);});
Kod ten oznacza dokładnie to samo co poprzedni zapis.
Do zaokrąglania liczb mamy metodę round, która jako argument pobiera wartość precyzji z jaką ma zostać wykonane zaokrąglanie.
Od razu kilka przykładów:
(12345.6789).round(3);
(12345.6789).round(2);
(12345.6789).round(1);
(12345.6789).round(0);
(12345.6789).round(-1);
(12345.6789).round(-2);
(12345.6789).round(-3);
Powyższe przykłady zwrócą kolejno:
12345.679
12345.68
12345.7
12346
12350
12300
12000
Jak widać im większa liczba tym większa precyzja, im mniejsza ujemna liczba tym bardziej zaokrąglona liczba.
Oczywiście jeżeli mocno przekroczymy wartość zaokrąglenia otrzymamy 0 tak jak w tym wypadku:
(12345.6789).round(-10);
Czasami musimy liczby ograniczyć do pewnego przedziału - w obiekcie Number służy do tego metoda limit, która jako dwa argumenty przyjmuje granice przedziału. Znów dla zrozumienia najlepiej będzie podać kilka przykładów:
125.limit(0,200);
125.limit(0,100);
125.limit(1000,2000);
Powyższe przykłady zwrócą kolejno:
125
100
1000
Jak widać w wypadku gdy liczba należy do danego przedziału, jej wartość nie ulega zmianie, ale już w momencie gdy leży poza jedną z granic przedziału, jej wartość jest ustala jako ta granica, którą dana liczba przekroczyła.
Na koniec nie można jeszcze pominąć kolejnego dużego usprawnienia zapisu. Jak pewnie zorientowani w JS wiedzą obliczenie takich wartości jak sinus danej liczby czy logartym przy danej podstawie wymaga użycia obiektu Math. Dobra wiadomość jest taka, że wszystkie metody obiektu Math przeniesiono do obiektu Number - można z nich korzystać na dwa sposoby:
Number.sin(3.14);
lub:
(3.14).sin();
Jak widać drugi zapis jest o krótszy niż tradycyjne:
Math.sin(3.14);
A przy tym wygląda jakoś tak bardziej uroczo (mam nadzieję, że nie jest to moja subiektywna opinia ;) ).
To teraz przykłady użycia wszystkich metod obiektu Math w nowym wydaniu:
(-25).abs();
(-1).acos();
(0).asin();
(0).atan();
(20).atan2(10);
(10.25).ceil();
(0).cos();
(0).exp();
(10.25).floor();
(1).log(1);
(100).max(10);
(100).min(10);
(100).pow(10);
(0).sin();
(2).sqrt();
(0).tan();
Jak widać zasada jest prosta - pierwszy argument funkcji w wersji z użyciem obiektu Math jest teraz obiektem do którego odnosi się dana metoda, a kolejne argumenty są podawane jako argumenty metody.
W kolejnej części kursu omówimy obiekt Hash i tym samym zakończymy omawianie obiektów natywnych w MooTools 1.2 .
Komentarze do wpisu "MooTools 1.2 - obiekty natywne - tekst i liczby":
1.
ubujamarek napisał(a):
17 lutego 2008, 19:37:07
Przepraszam ale masz chyba drobny błąd kilka linijek prze „Obiekt Number”
napisałeś:
Zwróci nam wartość false, bo element gh w tym ciągu rozdzielonym znakami „|” występuje.
A chciałeś chyba napisać że zwraca true
A tak ogólnie to bardzo lubię twój blog a szczególnie kurs mootools i dlatego głosuję na tak.
2.
Dziudek napisał(a):
17 lutego 2008, 20:55:21
@ubujamarek – rzeczywiście był błąd – już poprawiłem :) Dziękuję za informację i głos ;)
Dodaj komentarz: