Pokazywanie postów oznaczonych etykietą function. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą function. Pokaż wszystkie posty

sobota, 30 maja 2020

Function vs arrow function

Arrow function came in 2015 together with new ECMAScript 5. It was a revolution! No more var that = this; to be able to use parent context in a callback.

I really enjoyed this time and like others was using arrow functions everywhere. But 5 years later I started to hate arrow functions used as normal functions.

Code with one-liner functions and other variables:
const getData = dataKey => get(state, dataKey);
const makePlainObj = () => ({});
const doSth = ({ a, b }) => {console.log(b)};
const abc = { get: someFn };


Code with normal functions:
function getData(dataKey) {
  return get(state, dataKey);
}

function makePlainObj() {
  return {};
}

function doSth({ a, b }) {
  console.log(b);
}

const abc = { get: someFn };

Yes, second code is longer but at the same time much more readable. On first look it is visible what is a variable and what is a function. Also functions are hoisted when created as variables arrow functions are not.

czwartek, 3 września 2015

ES6 - arrows

The biggest difference between arrow and function is this value. Function uses its own this value, but arrow uses this value of the enclosing context.

Arrows are always anonymous functions!

Their syntax is slightly different than function expression:
(args) => { statements }


There could be few variations from this main version:
(arg1, arg2, argN) => { statements }
arg1 => { statements }
() => { statements }

(arg1, arg2, argN) => { statements }
(arg1, arg2, argN) => expression
(arg1, arg2, argN) => ({ prop: val })


It means - prentheses are optional. Mostly if there is only one argument, or only one value to return, this could be simplified.
But there is a catch:
(arg1, arg2, argN) => expression

but
(arg1, arg2, argN) => { return expression }


Example:
(arg1, arg2) => arg1 * arg2

(arg1, arg2) => { return arg1 * arg2 }


Both return the same, but we can write it in different way.

czwartek, 7 lutego 2013

lamanie zasad widzialnosci zmiennych w JavaScript

W poscie zasieg zmiennych (scope) w JavaScript opisalam jak wyglada widocznosc zmiennych w JavaScript. Podstawowa regula jest dosc jasna. Konkretny zasieg jest ograniczony przez funkcje. To co jest w srodku moze korzystac z tego co jest na zewnatrz, ale to co jest na zewnatrz nie ma dostepu do tego co jest w srodku.

var abc = "abc";

function xyz() {
  var def = "def";
}

console.log(abc);
console.log(def);

Wykonanie powyzszego kodu wyswietli abc oraz blad: ReferenceError: def is not defined. Zmienna def zostala zdefiniowana ze slowkiem var, przez co nie jest zmienna globalna, tylko lokalna we wlasnym scopie oraz scopach wewnetrznych. Z zewnatrz jej nie widac. Takie podejscie nazywamy zakresem statycznym lub leksykalnym (lexical scope). Tak na prawde o tym, gdzie sa jakie zmienne i jaki maja zasieg mozemy sie dowiedziec analizujac kod programu.

To na tyle powtorzenia. Czy istnieje sposob na udostepnienie zmiennych z wnetrza funkcji do globalnej przestrzeni nazw? Sprawdzmy.

Zalozmy, ze mamy taka strukture:

var a = "a";

function foo1 () {

  var b = "b";
  console.log(b);

  function foo2 () {

    var c = "c";
    console.log(c);

    console.log(b);

  }
}

foo1();
foo2();

Zasieg globlany wie o istnieniu zmiennej a i funkcji foo1. Reszta jest przed nim ukryta o czym swiadczy blad: ReferenceError: foo2 is not defined. Naszym celem jest wyciagniecie foo2 i jej zawartosci na swiatlo dzienne czyli do globalnej przestrzeni zmiennych.

Przede wszystkim zeby to zrobic musimy zmienic troszke podejscie. Statyczna prezentacja zakresow widzialnosci zmiennych nam tu nie pomoze. Do problemu trzeba podejsc dynamicznie!! Jedno z wielu rozwiazan podalam w poscie funkcje w JavaScript, part 5 - funkcje moga zwracac funkcje:

var a = "a";

function foo1 () {

  var b = "b";
  console.log("foo1 " + b);

  return function () {

    var c = "c";
    console.log("foo2 " + c);
    console.log("foo2 " + b);
  };
}

var foo2 = foo1();
foo2();

Jak widac na konsoli mamy wypisane foo1 b, ktore pochodzi z wykonania foo1 podczas przypisania tego co ona zwraca do foo2. Nastepnie wywolanie foo2 wypisuje foo2 c oraz foo2 b. Czyli z poziomu zasiegu globalnego mamy dostep do "wnetrznosci" foo1. Takie pamietanie przez funkcje swojego kontekstu nazywamy domknieciem (closure).

Innym sposobem na wykorzystanie domkniecia jest operowanie na zmiennych globalnych wewnatrz funkcji. Czym rozni sie zmienna globalna od zmiennej lokalnej w JavaScript? Slowkiem var:

var a = "a";

function foo1 () {

  var b = "b";
  console.log("foo1 " + b);

  foo2 = function () { // nie ma var

    var c = "c";
    console.log("foo2 " + c);
    console.log("foo2 " + b);
  };
}

foo1();
foo2();

Tutaj tak samo jak w poprzednim przykladzie istnienie foo2 zalezy od wykonania foo1. Foo2 nie istnieje, dopoki nie zostanie utworzone w foo1 jako zmienna globalna. Tutaj tez mamy domnkniecie, nasza zmienna globalna foo2 pamieta kontekst w ktorym zostala utworzona i wyswietla prawidlowo zmienna b.

środa, 6 lutego 2013

funkcje w JavaScript, part 5 - funkcje moga zwracac funkcje

Funkcje zawsze zwracaja jakas wartosc, nawet jesli jawnie nie jest zdefiniowane return (wtedy zwracaja undefined). Funkcja moze zwrocic tylko jedna wartosc, na przyklad tablice obiektow lub... inna funkcje:

function a() {
  console.log('A!');
  return function(){
    console.log('B!');
  };
}

a();

Jak widac, funkcja a() zwraca funkcje anonimowa. W momencie, gdy wywolamy a() na konsoli wypisze sie A!, kazde kolejne wywolanie a() ponownie wypisze tylko A! na konsoli. To co jest w return nie jest wykonywane w trakcie wolania funkcji, to jest to, co funkcja zwraca. To jak sie dobrac do tego co zwraca return?

var b = a();

a();
b();

Rozwiazaniem jest przypisanie wyniku dzialania funkcji do zmiennej. W tej sytuacji wywolanie a() nadal bedzie wypisywac A!, natomiast b(), do ktorego zostala przypisana funkcja anonimowa, ktora zwraca funkcja a(), bedzie wypisywac B!.

W ten sam sposob mozna zrealizowac nadpisanie (czy przepisanie) sie funkcji. Wystarczy pod wynik dzialania funkcji a() podstawic zmienna... a:

var a = a();

a();
a();

Tylko za pierwszym razem, w momencie przypisania wykonuje sie cialo oryginalnej funkcji a() i na konsoli pojawia sie A!. Po przypisaniu, funkcja a() przy kazdym wywolaniu na konsoli pisze B!, poniewaz teraz jej cialem stala sie funkcja anonimowa zwracana przez oryginalna funkcje a().

No dobrze, wszystko pieknie, ale co jesli funkcja anonimowa zwracana przez oryginalna funkcje a() korzysta z zakresu zmiennych dostepnych w oryginalnej funkcji a()? Ot, na przyklad:

function a() {
  console.log('A!');
  var abc = "abc";
  return function(){
    console.log(abc);
  };
}

Otoz, wszystko bedzie dzialac. Dla funkcji anonimowej scope zostanie zachowany (jak i dlaczego, o tym za chwile, w innym poscie):

var a = a();

a();
a();

Przy pisaniu na konsoli zobaczymy A!, natomiast kazde kolejne wywolanie a() wypisze juz na konsoli abc.

w sprawie samowywolujacych sie funkcji

Do postu o samowywolujacych sie funkcjach dostalam komentarz, bardzo trafny zreszta. Wiec postanowilam napisac kilka slow na ten temat.

Faktem jest, ze polskie tlumaczenie self-invoking nie jest jakos specjalnie udane, ale z braku lepszego uzywamy wlasnie okreslenia samowolajaca sie funkcja. Ale tak na prawde, dziekuje Ci Anonimowy Czytelniku, za podniesienie tej kwestii, ta funkcja jest wykonywana w miejscu w ktorym zostala w kodzie wstawiona. Sama sie nie wola, jest od razu wykonywana przez przegladarke. Oczywiscie dzieje sie tak dzieki dwom parom nawiasow okraglych, z ktorych jedna para obejmuje funkcje (jako calosc) a druga wskazuje ze jest to funkcja, dzieki czemu przegladarka ja wykonuje.

wtorek, 6 listopada 2012

funkcje w JavaScript, part 4 - funkcje prywatne

W poscie zasieg zmiennych (scope) w JavaScript pisalam o zasiegu zmiennych. Tworzenie funkcji prywatnych (lub wewnetrznych - private, inner functions) dziala w opisany w wyzej wymienionym poscie sposob:
function a {
  var abc = 12;
  function b () {
    console.log(abc);
  }
  b();
}

Funkcje sa danymi, wiec mozemy je definiowac wewnatrz innych funkcji. I zachowuja sie dokladnie tak samo jak zmienne. Jesli teraz wywolamy funkcje a:
a();

to na konsoli zostanie wypisana liczba 12. Jesli natomiast sprobujemy wywolac b:
b();

to otrzymamy ReferenceError: b is not defined. Ten sam blad (tylko z nazwa innej zmiennej) pojawi sie, jesli sprobujemy wyswietlic wartosc zmiennej abc. Zarowno funkcja b jak i zmienna abc sa zdefiniowane wewnatrz funkcji a, wiec sa widoczne tylko w jej wnetrzu, a poza nia srodowisko ich nie zna.

ś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.