środa, 31 października 2012

funkcje w JavaScript, part 3 - samowywolujace sie funkcje

Czyli self-invoking functions. Coz to takiego? Tak na prawde to kontynuacja tematu o funkcjach anonimowych.

Jak wyglada samowywolujaca sie funkcja? Jest to anonimowa funkcja otoczona nawiasami okraglymi, po ktorych jest jeszcze jedna para nawiasow okraglych i srednik.
(
  function() {
    // cialo funkcji
  }
)();

Jak to dziala? Otoz sama definicja funkcji anonimowej nie wnosi nic. Kod sie nie wykona automagicznie. Pierwsza para nawiasow opakowuje funkcje anonimowa, jako kod wykonywalny, a druga sluzy do przekazywania parametrow. Dosc czesto mozna spotkac sie z nastepujacym zapisem:
(
  function ($) {
    // cialo funkcji
  }
)(jQuery);

Jest to jeden z wielu sposobow na unikniecie konfliktu w przestrzeni nazw, gdy uzywa sie wiecej niz jednej biblioteki pozwalajacej na uzywanie znaku $ jako nazwy zmiennej. W pokazanym przykladzie sytuacja jest bardzo czysta. Wewnatrz funkcji znak dolara istnieje tylko jako obiekt jQuery.

Powyzszy zapis ma jedna zasadnicza wade. Ten kod mozna wykonac tylko raz, poniewaz nie ma nazwy. Uzycie funkcji anonimowej eliminuje zasmiecanie globalnej przestrzeni nazw, ale rownoczesnie uniemozliwia powtorne wykorzystanie kodu. Do czego wiec uzywa sie samowolajacych sie funkcji? Ogolnie do ustawiania srodowiska, jest to operacja wykonywana zazwyczaj raz, przy inicjalizacji.

poniedziałek, 29 października 2012

funkcje w JavaScript, part 2 - funkcje anonimowe

We wczesniejszym poscie pisalam, ze funkcje mozna definiowac, jak zmienne. Tak wiec skoro zapis:
var a = 5;

jest poprawny, tak samo zapis:
var b = function(){};

tez jest poprawny. Ale idac za ciosem, zapis:
5;

tez jest poprawny, choc nic nie wnosi. Ot sama wartosc. W takim badz razie zapis:
function(){};

tez jest poprawny, choc w takiej postaci tez nic nie wnosi. Powyzsza definicja funkcji bez podania nazwy jest okreslana funkcja anonimowa (anonymous function).

Do czego mozna uzyc takiego tworu? Najczesciej przekazuje sie jako parametr do innej funkcji (funkcje sa danymi, wiec mozna je przekazywac jako parametry), tzw anonymous callback function, lub wywoluje w specyficzny sposob.

Anonymous callback function:
function fa () {

var a = 12;

var b = function(va, vb) {
  console.log("va = " + va);
  console.log("vb() returns " + vb());
}

b(a, function(){ return a + 2;});

}

fa();

Kod stosunkowo prosty. Ot mamy funkcje fa. W srodku definiujemy zmienna a oraz funkcje prywatna b (niewidoczna z zewnatrz, ale o tym w innym poscie). Funkcja b przyjmuje 2 parametry, drugi jest funkcja. Oba parametry wyswietla na konsoli. Nastepnie wolamy funkcje b przekazujac jako pierwszy parametr zmienna a, a jako drugi funkcje anonimowa w ktorej modyfikujemy a dodajac do niej 2. Na koncu wywolujemy fa.

I tu pojawia sie pytanie, po co przekazywac funkcje anonimowa jako parametr do innej funkcji? Przeciez mozna zapisac (a + 2) i przekazac jako zwykla liczbe. To oczywiscie byl prosty przyklad. Funkcja anonimowa dziala, jak kazda inna, ma swoj wlasny scope, ale i widzi zmienne ze srodowiska w ktorym sie znajduje. Daje nam to duze mozliwosci uzywania zmiennych dostepnych i manipulowania nimi bez zasmiecania przestrzeni nazw kolejna nazwa funkcji uzyta w jednym tylko miejscu. Opakowuje ladnie kod, dzieki czemu wprowadzanie zmian jest latwiejsze.

Wyobrazmy sobie, ze mamy tablice po ktorej sie iterujemy i kazdy element modyfikujemy. Iteracja po tablicach czy obiektach jest zasobozerna. Im wieksza tablica, tym wiekszy czas wykonania iteracji i tym wiecej zasobow jest wykorzystanych. Optymalizacja w takich wypadkach polega na tym, aby ograniczyc sie do jednej iteracji i zmniejszyc czas wykonania operacji na kazdym elemencie. Najszybciej wykonuje sie kod napisany inline, ale kazdy programista z choc minimalnym doswiadczeniem wie, jak trudno jest utrzymac kod napisany inline. Dlatego wykorzystuje sie funkcje anonimowe, ktore daja swoj narzut na wykonanie kodu, ale go rownoczesnie porzadkuja i ulatwiaja wprowadzanie zmian i utrzymanie.

Jak widac, powodow uzywania funkcji anonimowych jako parametrow jest wiele, najczesciej zwiazane sa one z optymalizacja kodu i/lub jego czytelnoscia.

A tutaj przykład użycia samowywołujacej się funkcji anonimowej

piątek, 26 października 2012

funkcje w JavaScript, part 1 - sposoby definiowania

W JavaScript mamy dwa sposoby definiowania funkcji. Jeden to znany z innych jezykow sposob polegajacy na uzyciu slowa kluczowego function:
function abc () {
  // cialo funkcji
  return;
}

Drugi wymaga krotkiego wprowadzenia. W JavaScript funkcje sa nie tylko funkcjami, ale rowniez danymi, w zwiazku z powyzszym mozna je zdefiniowac, jak zmienna:
var xyz = function() {
  // cialo funkcji
  return;
};

W obu przypadkach wywoluje sie je tak samo:
abc();
xyz();

Tak wiec funcje w JavaScript sa danymi, ale specyficznymi i posiadaja dwie bardzo wazne wlasciwosci: zawieraja kod i sa wykonywalne.

Jesli uzyjemy operatora typeof na nazwach obu funkcji, za kazdym razem dostaniemy wynik "function".
console.log("abc jest typu " + typeof(abc));
console.log("xyz jest typu " + typeof(xyz));

Tak wiec mimo roznicy w sposobie definiowania jest to wciaz funkcja.

wtorek, 23 października 2012

zasieg zmiennych (scope) w JavaScript

Czytam sobie ostatnio do poduszki obiektowy JS, tak w ramach powtorzenia. Poniewaz dziergam w tym jezyku kilka lat juz coraz mniej mnie dziwi. Aczkolwiek kwestia, z ktora sobie dosc dlugo nie moglam poradzic byl zasieg zmiennych.

Zalozmy ze mamy kod:
var a = 1;
function f() {
   console.log('1. ' + a);
   var a = 2;
   console.log('2. ' + a);
}

f();

Zasieg zmiennych w JS jest ograniczony nie do nawiasow klamrowych, a do funkcji (od ES6 tylko dla słowa kluczowego var). Jesli zmienna jest w globalnej przestrzeni nazw (bez slowka var) to jest osiagalna praktycznie z dowolnego miejsca. Slowko var ogranicza zasieg, np do danego pliku czy funkcji.

Co bedzie wynikiem dzialania takiego kodu? Otoz zmienne sa widoczne w srodowiskach zawartych, ale nie na zewnatrz. Wiec jesli na zewnatrz funkcji mamy zdefiniowana zmienna a, a wewnatrz funkcji tworzymy ja jeszcze raz (slowko var), to JavaScript bedzie widzialo ta zmienna wewnatrz funkcji, jako zmienna o zasiegu tylko na te funkcje. Zaskutkuje to tym, ze pierwszy console.log wypisze nam undefined. Dlaczego? Bo wewnatrz funkcji ta zmienna JESZCZE nie ma wartości (interpreter już wie, że będzie stworzona, ale jeszce w tej linii kodu nie ma wartości; stąd dobra praktyka tworzyć WSZYSTKIE zmienne na początku funkcji/bloku kodu, żeby uniknąć takich sytuacji), wiec by default ma przypisana wartosc undefined. Drugi console.log wypisze juz, zgodnie z oczekiwaniami wartosc 2.


Zmodyfikujmy troche nasz kod:
var a = 1;
function f() {
   console.log('1. ' + a);
   a = 2;
   console.log('2. ' + a);
}

f();

Mala roznica. Wenatrz funkcji usunelam slowo var przed definicja zmiennej lokalnej a. Co to zmienia z punktu widzenia naszego programu? Wszystko. Przede wszytkim JavaScript sprawdzi, czy w zasiegu dostepnym z wnetrza funkcji nie ma juz zmiennej a. Jesli jest (jak w naszym przypadku) to zmieni jej wartosc.

Nasz program wypisze dwa razy wartosc zmiennej a widoczna wewnatrz funkcji. Za pierwszym razem bedzie to 1, a za drugim 2 (wartosc zmieniona juz wewnatrz funkcji)


To teraz tylko sprawdzenie, jak to wyglada na zewnatrz funkcji:
var a = 1;
function f() {
   console.log('1. ' + a);
   a = 2;
   console.log('2. ' + a);
}

console.log('3. ' + a);

f();

console.log('4. ' + a);

Zgodnie z oczekiwaniami zmienna istnieje w kazdym przypadku i zmiana jej wartosci wewnatrz funkcji skutkuje zmiana rowniez poza funkcja, bo operujemy na zmiennej o zakresie szerszym niz zakres tej funkcji.

niedziela, 14 października 2012

CSS3 Media Queries, IE 8 i starsze oraz fixy w js

Frontendowcy bawiacy sie w responsive design znaja pojecie media queries bardzo dobrze, podobnie jak i fluid layout. Tym razem zajmiemy sie css3 media queries i ich wykrywalnoscia przez... the winner is... IE8 i starsze, jak zwykle.

Na stronie Can I use? mozna sprawdzic dostepnosc roznych elementow CSS3 i HTML5 w roznych przegladarkach (rowniez mobilnych). Jak widac, CSS3 Media Queries nie sa obslugiwane przez IE8 i starsze (co nas w sumie nie dziwi...). To co ma zrobic frontendowiec chcacy zrobic strone zgodna ze wszystkimi zasadami i ladnie wyswietalajaca sie w roznych rozdzielczosciach?

Jak zwykle w takich przypadkach siegamy po pomoc JS. Polecam skrypt respond.js. Wystarczy sciagnac wersje mini, wrzucic do sekcji head i...

No wlasnie i wszystko zalezy od tego, czy nasza responsywna stronke piszemy lokalnie czy na serwerze. Bo jesli lokalnie, to nasze zabiegi majace na celu nauczenie IE 8 i starszych jak rozumiec CSS3 Media Queries nie odniosa zadnego skutku. Zeby cokolwiek zadzialalo, pliki musza byc serwowane z serwera.

filter: progid:DXImageTransform.Microsoft.gradient nie dziala w IE7

A zdarza sie, ze mamy, kilka dzialajacych gradientow i jeden ni z gruszki ni z pietruszki nie dziala. Co pomoze?

Dodanie wysokosci w kontenerze lub overflow:auto;.

czwartek, 11 października 2012

Puste miejsca miedzy <LI> w IE 7/8

W internecie znalazlam milion piecset rozwiazan. Ale najlepsze, bez komplikowania kodu, jest usuniecie znakow entera, spacji czy innych spomiedzy LI w kodzie.

Czyli zamiast:
<LI>text</LI>
<LI>text</LI>
<LI>text</LI>

zrobmy:
<LI>text</LI><LI>text</LI><LI>text</LI>

Juz slysze te glosy niezadowolenia, ze wtedy dluga linia, ze nieczytelne, trudne w utrzymaniu... Zgadzam sie, dlatego w ramach ulepszania kodu wystarczy zrobic cos takiego:
<LI>text</LI><LI>
text</LI><LI>
text</LI>

Gra i buczy.