W drugiej i ostatniej części kursu poświęconej metodom obiektu Array jakie oferuje nam MooTools 1.2 zajmiemy się rozszerzaniem tablicy o wiele elementów naraz (metody extend i combine), usuwaniu tablic zagnieżdżonych (metoda flatten), tworzeniem obiektów (a właściwie hashy) na bazie tablic (metody associate i link) oraz konwersjami kolorów z formatu RGB na heksadecymalny i odwrotnie.

Gdy push i include nie wystarczają

Nieraz podczas programowania zdarzy się sytuacja w której będziemy potrzebować dodać do istniejącej tablicy kilka elementów naraz. Oczywiście można zrobić to w pętli i wykorzystać chociażby metodę push. Jednak po co zapisywać zbędny kod, jeżeli możemy zrobić to za pomocą jednej krótkiej linijki - dzięki metodzie extend:

[1, 2, 3, 4, 5].extend([5, 6, 7, 8, 9, 10]);

Jak widać metoda extend pobiera jeden argument - tablicę do scalenia z istniejącą już tablicą. W efekcie działania tej metody otrzymamy następującą tablicę:

[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]

Widać, że nastąpiło powielenie elementu o wartości 5. Dzieje się tak dlatego, ponieważ metoda extend bazuje na innej metodzie obiektu Array - metodzie push. Gdybyśmy chcieli jednak uzyskać efekt podobny do działania metody include (czyli brak możliwości powielenia elementu dodawanego w tablicy wynikowej), to musimy skorzystać z metody bazującej na include, czyli metody combine:

[1, 2, 3, 4, 5].combine([5, 6, 7, 8, 9, 10]);

W rezultacie uzyskamy tablicę:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Która posiada unikalne elementy.

Podsumowując ten fragment - odpowiednikiem metody push przy dodawaniu kilku elementów naraz do danej tablicy jest metoda extend, a w wypadku metody include jest to metoda combine.

Usuwanie zagnieżdżonych tablic

Gdyby zaszła potrzeba zamiana tablicy postaci (nie ukrywajmy - lekko zagmatwanej):

[[1, [2, [3, 4, [5, [6, [7]]], 8, 9, 10]]], [[[[11]], [12]]]]

Na tablicę zawierającą elementy o wartościach od 1 do 12, bez żadnych zagnieżdżonych tablic, to możemy skorzystać z metody flatten:

[[1, [2, [3, 4, [5, [6, [7]]], 8, 9, 10]]], [[[[11]], [12]]]].flatten();

W wyniku jej działania uzyskamy nową, o wiele czytelniejszą formę wspomnianej tablicy:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Tworzymy obiekty na bazie tablic

Jak pewnie wiecie obiekty składają się z par właściwość-wartość, dlatego też przydatna może niektórym wydać się możliwość stworzenia obiektu z dwóch tablic, z których jedna zawiera właściwości, a druga wartości - taką metodą jest associate:

tablicaWartosci.associate(tablicaWlasciwosci);

Na przykład stwórzmy obiekt w którym każdej właściwości będzie odpowiadał kwadrat jej wartości:

[1, 2, 9, 16, 25].associate([1, 2, 3, 4, 5]);

W rezultacie otrzymamy obiekt następującej postaci:

{
    1: 1,
    2: 4,
    3: 9,
    4: 16,
    5: 25
}

Czasem może się okazać, że znamy typ poszczególnych właściwości obiektu i potrzebujemy im przypisać na bazie tablicy wartości danego typu. Do tego celu służy metoda link:

tablicaWartosci.link(obiektWzorzecDopasowan);

W powyższym zapisie tablicaWartosci to po prostu tablica z elementami (z reguły różnych typów), a obiektWzorzecDopasowan to obiekt, gdzie wartości poszczególnych właściwości określają typu obiektów natywnych. Na przykład: jeżeli chcemy w danym miejscu umieścić cyfrę zapisujemy Number.type, jeżeli ma być to ciąg znaków zapisujemy String.type itd.

[1,2,3,'a','b'].link({
    "Liczba testowa" : Number.type,
    "Znak testowy" : String.type
});
 

W rezultacie otrzymamy obiekt postaci:

{
    "Liczba testowa" : 1,
    "Znak testowy" : 'a'
}

Co świadczy o tym, że wykorzystywane jest pierwsze dopasowanie do danego typu. Gdybyśmy chcieli dopasować wszystkie elementy tablicy, musimy stworzyć odpowiednią ilość właściwości:

[1,2,3,'a','b'].link({
    "Jeden" : Number.type,
    "Litera a" : String.type,
    "Dwa" : Number.type,
    "Trzy" : Number.type,
    "Litera b" : String.type
});

W rezultacie uzyskamy obiekt postaci:

{
    "Jeden" : 1,
    "Litera a" : 'a',
    "Dwa" : 2,
    "Trzy" : 3,
    "Litera b" : 'b'
}

Konwersje kolorów

Do omówienia pozostała nam jeszcze kwestia konwersi kolorów w formacie RGB na format heksadecymalny i odwrotnie. Służą do tego metody rgbToHex i hexToRgb.

Metoda rgbToHex operuje na tablicach trójelementowych oraz czteroelementowych- w zalezności od tego czy korzystamu z formatu RGB czy RGBA. Dodatkowo może ona pobierać jeden parametr, będący wartością logiczną, który pozwala określić czy metoda zwrócić obiekt typu String czy też tablicę:

[10, 20, 30].rgbToHex();

Powyższy kod zwróci nam:

"#0a141e"

Gdybyśmy chcieli uzyskać ten sam kolor w postaci tablicy - zapiszemy:

[10, 20, 30].rgbToHex(true);

Uzyskując tym samym:

["0a", "14", "1e"]

Warto jeszcze wspomnieć, że jeżeli ustawimy wartość 0 dla parametru alpha koloru:

[10, 20, 30, 0].rgbToHex();

To usyskamy rezultat:

"transparent"

Ale tylko i wyłącznie gdy ustawimy zwracanie rezultatu jako obiekt typu String, w przeciwnym wypadku uzyskamy zwykłą tablicę wartości heksadecymalnych.

Jeżeli chodzi o konwersję w drugą stronę to działa ona tak samo tylko musimy operować tablicy wartości heksadecymalnych:

["10", "20", "30"].hexToRgb(true);

Powyższy kod zwróci nam:

[16, 32, 48]

Natomiast po wykonaniu:

["10", "20", "30"].hexToRgb();

Otrzymamy ciąg znaków:

"rgb(16,32,48)"

Podsumowanie

W ten oto sposób poznaliśmy wszystkie nowe możliwości obiektu Array jakie uzyskamy korzystając z MooTools. W kolejnej części kursu zajmiemy się obiektem natywnym Function.

Komentarze do wpisu "MooTools 1.2 - tablice w MooTools cz.2":

1. Rafael napisał(a):
08 lipca 2008, 22:10:13

W zasadzie metoda Array.extend działa prawie tak samo jak natywna metoda Array.concat
var a=[1, 2, 3, 4], b=a.concat([5, 6, 7, 8]);
Jedyna różnica polega na tym, że .extend modyfikuje oryginalną tablicę, a .concat zwraca nową tablicę stworzoną na podstawie oryginalnej i tablicy przekazanej jako argument i w dodatku ma więcej możliwości (można od razu dołączyć więcej tablic, czy całą listę pojedynczych wartości).

Swoją drogą dziwi mnie trochę fakt, że implementacja tej metody korzysta z pętli (okolice linii 483)

extend: function(array){ for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); return this; },
można to zapisać jedną instrukcją
extend: function(array){ this.push.apply(this,array); return this; },

Przyznam się, że nie badałem sprawy, jest to tylko moja luźna opinia. Może był jakiś konkretny powód (wydajność? Ciężko uwierzyć)

2. Dziudek napisał(a):
08 lipca 2008, 22:14:59

@Rafael – osobiście mam dwie teorie ;) Albo na jakiejś dziwnej przeglądarce typu IE6 to nie działało (choć cudów w tym kodzie nie ma, ale IE6 (a nawet IE7) na banalniejszych fragmentach się wykłada), albo też po prostu zespół MooTools niezbyt się przykładał do Natives – generalnie o ile pamiętam Natives to jedna z bardziej zaniedbanych sekcji w MooTools, bo dość rzadko ją aktualizowali ;)

3. Rafael napisał(a):
08 lipca 2008, 22:47:31

Dla pewności sprawdziłem w standardzie ECMA-Scriptu, czy .push przyjmuje dowolnie długą listę argumentów .push(arg1, arg2, ..., argN) i rzeczywiście tak jest, więc nie jest to jakieś rozszerzenie Gecko, czy coś w tym stylu.

Przeprowadziłem szybki test. Wygląda na to, że jednak mamy do czynienia z sprawą wydajności, choć różnica czasowa nie była tak wielka. Z jednej strony, ciężko mi uwierzyć, że natywna metoda wywołana metodą apply działa wolniej od pętli+.push… ale po krótkim namyśle – jednak wywołanie .apply też coś kosztuje… trzeba w końcu całą tablicę przerobić na argumenty metody .push (nie wiem, jak to w silniku jest realizowane, ale na pewno coś na ten wzór) i w pętli wykonywanie czynności dodawania elementów.

Może jednak ta część Mootoolsa nie jest aż tak zaniedbana ;-P

4. Dziudek napisał(a):
08 lipca 2008, 22:50:29

@Rafael – może nie jest zaniedbana, ale na pewno sprawia wrażenie takiej „jak dobrze działa to lepiej nie ruszajmy” :) Dzięki, że to zweryfikowałeś ;) Dla programistów MooTools jednak nawet te ułamki sekund robią różnicę zwłaszcza, że przy większej częstości użycia metody robią się z nich sekundy itd. ;)

Dodaj komentarz:

Textile Lite włączony ( szczegółowy opis znaczników ):
*strong* | # lista numerowana | * lista wypunktowana | _em_ | __italic__ | "link":http:// | bq. cytat.