Funkcje
Co to są funkcje w JavaScript?
Funkcja w JavaScript to potencjalnie reużywalny zestaw wyrażeń (ang. expressions) oraz instrukcji (ang. statements), który akceptuje zero lub więcej parametrów i może zwracać wartość.
W JavaScript funkcja może zostać utworzona poprzez:
-
deklarację funkcji lub
-
wyrażenie funkcji.
Deklaracja funkcji
Deklaracja funkcji to utworzenie funkcji i powiązanie tej nowo-utworzonej funkcji z identyfikatorem, do którego można odwoływać się poza zakresem tej funkcji.
Deklaracja funkcji polega:
-
użyciu słowa kluczowego
function
z dodanym wymaganym identyfikatorem, stanowiącym nazwę tej funkcji, -
dodaniu zero, jednego lub więcej parametrów zawartych w nawiasach i rozdzielonych przecinkami, oraz
-
dodaniu bloku kodu zawartego w nawiasach klamrowych, ale
-
nieprzypisywaniu tak utworzonej funkcji do zmiennej, ani
-
nieprzypisywaniu tak utworzonej funkcji do właściwości obiektu, ani
-
niezawieraniu tak utworzonej funkcji w nawiasach.
function dodaj(a, b) {
return a + b
}
dodaj(2, 2) // => 4
// Deklaracja funkcji wiąże tę funkcję z identyfikatorem.
const dodaj = 'foo' // Uncaught SyntaxError: Identifier 'dodaj' has already been declared
Wyrażenie funkcji
Wyrażenie funkcji to utworzenie funkcji bez wiązania tej nowo-utworzonej funkcji z identyfikatorem, do którego możnaby się odwoływać poza zakresem tej funkcji.
Wyrażenie funkcji może nastąpić poprzez:
-
użycie słowa kluczowego
function
i spełnienie określonych warunków, albo -
użycie składni strzałkowej (arrow syntax).
Wyrażenie funkcji z użyciem słowa kluczowego `function`
Wyrażenie funkcji przy użyciu słowa kluczowego function
polega na:
-
użyciu wspomnianego słowa kluczowego
function
wraz z opcjonalnym identyfikatorem, stanowiącym nazwę tej funkcji, -
dodaniu zero, jednego lub więcej parametrów zawartych w nawiasach i rozdzielonych przecinkami, oraz
-
dodaniu bloku kodu zawartego w nawiasach klamrowych, przy jednoczesnym
-
przypisaniu tak utworzonej funkcji do zmiennej, lub
-
przypisywaniu tak utworzonej funkcji do właściwości obiektu, lub
-
zawarciu tak utworzonej funkcji w nawiasach.
Wyrażenie funkcji polegające na utworzoniu funkcji wraz z przypisaniem takiej funkcji do zmiennej:
const foo = function odejmij(a, b) {
return a - b
}
// Nie następuje utworzenie powiązania funkcji z identyfikatorem 'odejmij'.
odejmij(4, 2) // Uncaught ReferenceError: odejmij is not defined
// Następuje przypisanie funkcji do zmiennej 'foo'.
foo(4, 2) // => 2
Wyrażenie funkcji polegające na utworzeniu funkcji wraz z przypisaniem takiej funkcji do właściwości obiektu:
const foo = {
bar: function odejmij(a, b) {
return a - b
}
}
// Nie następuje utworzenie powiązania funkcji z identyfikatorem 'odejmij'.
odejmij(4, 2) // Uncaught ReferenceError: odejmij is not defined
// Następuje przypisanie funkcji do właściwości `bar` obiektu 'foo'.
foo.bar(4, 2) // => 2
Wyrażenie funkcji polegające na utworzeniu funkcji wraz z zawarciem takiej funkcji w nawiasach.
(function odejmij(a, b) {
return a - b
})
// Nie następuje utworzenie powiązania funkcji z identyfikatorem 'odejmij'.
odejmij(4, 2)
Wyrażenie funkcji używające słowa kluczowego function, może, ale nie musi zawierać nazwy funkcji. Wyrażone funkcje bez nazwy nazywane są funkcjami anonimowymi.
(function(a, b) {
return a + b
})(2, 2) // => 4
const dodaj = function(a, b) { return a + b }
dodaj(2, 2) // => 4
Wyrażenie funkcji z użyciem składni strzałkowej
Innym sposobem na wyrażenie funkcji, niż użycie słowa kluczowego function
, jest użycie funkcji strzałkowej (arrow function), która to możliwość wprowadzona została przez ES6.
Funkcje strzałkowe nie mogą mieć przypisanej nazwy, a więc są zawsze anonimowe.
const dodaj = (a, b) => { return a + b }
dodaj(2, 2) // => 4
Nawiasy klamrowe oraz słowo kluczowe return
mogą być pominięte w jednolinijkowych funkcjach strzałkowych, a wtedy funkcja ta zwraca wyrażenie zawarte w jej ciele.
const dodaj = (a, b) => a + b
dodaj(2, 2) // => 4
Parametryzacja funkcji
Funkcje w JavaScript mogą przyjmować zero, jeden lub więcej parametrów.
Parametry mogą być użyte w ciele funkcji i wpływać na wyrażenia i stwierdzenia zawarte w ciele funkcji, a tym samym na zwracaną wartość oraz efekty uboczne wykonywane przez tę funkcję.
Wpływ parametrów na zwracaną wartość:
function dodaj(a,b) {
return a + b
}
dodaj(2,2) // => 4
dodaj(2,3) // => 5
dodaj(3,3) // => 6
Wpływ parametrów na efekty uboczne:
const foo = { bar: 'baz' }
function zmienObiekt(o, n) {
o.bar = n
}
zmienObiekt(foo, 'qux')
foo // => { bar: 'qux' }
Parametry vs argumenty
Przyjmuje się, że nazwy znajdujące się w nawiasach podczas tworzenia funkcji określa się parametrami. Podczas, gdy rzeczywiste wartości podawane przy wywoływaniu funkcji nazywa się argumentami. Vide JavaScript Function Parameters.
function dodaj(a, b) { // a oraz b to parametry.
return a + b
}
dodaj(2, 3) // 2 oraz 3 to argumenty.
Przekazywanie argumentów przez wartość
Wartości o prymitywnych typach danych, takich jak na przykład number
, string
lub boolean
, gdy podawane są do funkcji w trakcie jej wywoływania jako argumenty, przekazywane są przez wartość a nie jako kopie.
Z kolei wartości będące obiektami, gdy podawane są do wywoływanej funkcji jako argumenty, mają referencje do samych siebie skopiowane a następnie te kopie referencji są przekazywane do tej funkcji. Oznacza to, że obiekty, gdy są podawane do funkcji jako argumenty, nie są przekazywane jako kopie (tylko referencje do nich są kopiowane), a również przez wartość.
Oznacza to, że przypisanie nowej wartości do argumentu funkcji nie ma wpływu na wartość, która została podana jako ten argument, poza zakresem tej funkcji.
const kapitanowieEnterprise = { najlepszy_kapitan: 'Picard' }
function zastapKapitanow(kapitanowie) {
kapitanowie = { najlepszy_kapitan: 'Hook' }
}
zastapKapitanow(kapitanowieEnterprise)
kapitanowieEnterprise // => { najlepszy_kapitan: 'Picard' }
Natomiast, jako, że obiekty nie są przekazywane do funkcji jako kopie, a jako wartości, to zmiana takiego obiektu w ciele funkcji wpływa na ten obiekt ogólnie - w zakresie, jak i poza zakresem, tej funkcji.
const kapitanowieEnterprise = { najlepszy_kapitan: 'Picard' }
function zmienKapitanow(kapitanowie) {
kapitanowie.najlepszy_kapitan = 'Janeway'
}
zmienKapitanow(kapitanowieEnterprise)
kapitanowieEnterprise // => { najlepszy_kapitan: 'Janeway' }
Zwracanie wartości przez funkcję
Wywołana funkcja:
-
zwraca wartość wyrażnie wskazaną, gdy zostanie użyte słowo kluczowe
return
, a jej wywoływanie nie zostanie wstrzymane, -
zwraca
undefined
, gdy słowo kluczowereturn
nie zostanie użyte, a jej wywoływanie nie zostanie wstrzymane, -
zwraca
this
, gdy zostanie wywołana przy użyciu słowa kluczowegonew
jako konstruktor, a jej wywoływanie nie zostanie wstrzymane, -
nic nie zwraca, gdy jej wywoływanie zostanie wstrzymane ze względu na błąd.
Zwrócenie wartości wyraźnie wskazanej poprzez użycie słowa kluczowego return
:
function dodaj(a, b) {
return a + b
}
// Funkcja `dodaj` zwraca `4`, które następnie zostaje przypisane do zmiennej `suma`.
const suma = dodaj(2, 2)
suma // => 4
Zwrócenie undefined
poprzez pominięcie słowa kluczowego return
:
function tylkoZaloguj() {
console.log('tylko loguje')
}
const foo = tylkoZaloguj() // tylko loguje
foo // => undefined
Zwrócenie this
poprzez użycie słowa kluczowego new
:
function Osoba(imie) {
this.imie = imie
}
const wiedzmin = new Osoba('Geralt')
wiedzmin // => Osoba {imie: 'Geralt'}
Nie zwrócenie niczego ze względu na wyrzucenie błędu podczas wykonywania funkcji:
function dodaj(a, b) {
return aa + b
}
Funkcje jako obywatele pierwszej klasy (first-class citizens)
Funkcje w JavaScript są tak zwanymi obywatelami pierwszej klasy (first-class citizens), co oznacza, że mogą być:
-
przekazywane jako argumenty do innych funkcji,
-
zwracane jako wartości z innych funkcji, oraz
-
przypisywane do zmiennych lub właściwości obiektów.
Przekazanie funkcji jako argumentu:
function wykonajMnie(funkcjaDoWykonania) {
funkcjaDoWykonania()
}
function zalogujFoo() {
console.log('foo')
}
function zalogujBar() {
console.log('bar')
}
wykonajMnie(zalogujFoo) // foo
wykonajMnie(zalogujBar) // bar
Zwrócenie funkcji jako wartości z innej funkcji:
function utworzFunkcjeMnozaca(mnoznik) {
return (mnozna) => mnozna * mnoznik
}
utworzFunkcjeMnozaca(2)(21) // => 42
Funckja może zostać przypisana do zmiennej lub właściwości obiektu:
const zalogujFoo = () => console.log('foo')
zalogujFoo()
const mapaLogerow = {
zalogujFoo: () => console.log('foo'),
zalogujBar: () => console.log('bar')
}
mapaLogerow.zalogujFoo() // foo
mapaLogerow.zalogujBar() // bar
const tablicaLogerow = [
() => console.log('foo'),
() => console.log('bar')
]
tablicaLogerow[0]() // foo
tablicaLogerow[1]() // bar
Funkcje wyższego rzędu /higher-order functions/
Gdy funkcja przyjmuje inną funkcję jako argument lub zwraca inną funkcję nazywana jest funkcją wyższego rzędu /higher-order function/. Pozostałe funkcje nazywane są funkcjami pierwszego rzędu /first-order functions/.
Przykładem funkcji wyższego rzędu jest funkcja map
, której pierwszym parametrem jest funkcja.
const liczby = [1,2,3]
liczby.map(function(liczba) { return liczba * 2 }) // => [2,4,6]
Podnoszenie /hoisting/
TODO
TODO
TODO
Function declarations are hoisted, initialized with the declared value and can be called in a given scope before their actual declaration. Compare it to hoisting of var
, let
, and const
.
sum(2, 2) // => 4
function sum(a, b) { return a + b }
Recursion
A function can call itself in three ways: 1) through calling its declared name, 2) through calling the reference to itself, and 3) through calling arguments.callee
from within its body.
Closures
Functions in JavaScript are closures which mean they carry with themselves variables, constants and function declarations declared outside of their bodies but used within their bodies.