Funkcje
Co to są funkcje
Funkcje to zbiór zgrupowanych instrukcji, które możemy odpalać poprzez podanie ich nazwy. Każda taka funkcja po wywołaniu wykonuje swój wewnętrzny kod, a następnie może zwrócić nam jakąś wartość.
Ogólna deklaracja funkcji ma postać:
function nazwaFunkcji(nr) {
const result = nr * nr; //możemy też po prostu zwrócić nr * nr
return result;
}
//Po stworzeniu funkcji wystarczy ją wywołać poprzez podanie jej nazwy:
nazwaFunkcji(2); //4
nazwaFunkcji(3); //9
nazwaFunkcji(5); //25
Funkcję można traktować jak swego rodzaju podprogramy (autor lubi nazywać je klockami, ale, że niektórym dziwnie to się kojarzy...), które w każdej chwili możemy odpalić by wykonać dany kod. Takie funkcje możesz spokojnie trzymać w oddzielnym pliku, który potem będziesz dołączać do wybranych stron. Na tej właśnie zasadzie używa się znanych bibliotek - np. jQuery, Lodash czy podobnych, które są niczym innym jak zbiorem funkcji, które ktoś dla nas napisał.
W tym kursie już nie raz używałeś funkcji:
alert("Ala ma kota");
Math.random();
Math.max(1,2,3);
"ala ma kota".toUpperCase();
"kot i pies".substr(1);
[1,2,3].push(4);
[1,2,3].join("-");
Widzisz te nawiasy na końcu każdej linii? Poprzedza je nazwa danej funkcji. Autorzy JavaScript przygotowali dla nas zestaw funkcji. Miło z ich strony...
Parametry funkcji
Dla każdej funkcji możemy utworzyć parametry. Dzięki nim przy odpalaniu będziemy mogli podawać dla danej funkcji jakieś wartości:
function sum(a, b) {
return a + b;
}
console.log( sum(2, 3) ); //5
console.log( sum(4, 3) ); //7
function lineText(name, pet) {
console.log(name + " ma " + pet);
}
lineText("Ola", "kota"); //Ola ma kota
lineText("Ala", "psa"); //Ala ma psa
Jeżeli nasza funkcja wymaga pewnych wartości, a my ich nie podamy, zostaną użyte dla nich wartości undefined
:
function writeText(name, age) {
console.log(`${name} ma kota, który ma ${age} lat`);
}
writeText("Ala", 5); //"Ala ma kota, który ma 5 lat"
writeText("Marysia"); //"Marysia ma kota, który ma undefined lat"
writeText(); //"undefined ma kota, który ma undefined lat"
Wartości do funkcji musimy przekazywać w takiej kolejności, jakiej wymaga tego dana funkcja. Możemy to jednak ominąć za pomocą tak zwanej destrukturyzacji.
Domyślne wartości
Jeżeli funkcja wymaga podania wartości przy jej wywołaniu, a my ich nie podamy, w jej wnętrzu będą one wynosić undefined
:
function printText(txt) {
console.log("Twój tekst to " + txt);
}
printText("kot"); //"Twój tekst to kot"
printText(); //"Twój tekst to undefined"
Dla parametrów możemy też ustawiać domyślne wartości. Wystarczy po nazwie parametru ustawić mu domyślną wartość:
function print(name = "Michał", status = "najlepszy") {
console.log(name + " jest " + status);
}
print(); //"Michał jest najlepszy"
print("Karol"); //"Karol jest najlepszy"
print("Paweł", "wysoki"); //"Paweł jest wysoki"
print(undefined, "wysoki"); //"Michał jest wysoki" - undefined jest traktowane jak niepodanie wartości
W poprzednich wersjach JavaScript domyślne atrybuty nie istniały, ale i na to były sposoby.
arguments i rest
JavaScript nie wymaga od nas, abyśmy przekazywali do funkcji wymaganą przez daną funkcję ilość wartości.
Jeżeli nie zakładamy konkretnej liczby parametrów dla funkcji, możemy skorzystać z właściwości arguments, która zawiera w sobie wszystkie przekazane wartości:
function sum() {
console.log(arguments);
}
sum(); //[] Arguments
sum(1, 2, 3, 4); //[1, 2, 3, 4] Arguments
sum("ala", "ma", "kota"); //["ala", "ma", "kota"] Arguments
Obiekt arguments jest tablico podobny, ale tak naprawdę nie jest tablicą.
Oznacza to, że nie możemy na nim wykonywać metod przeznaczonych dla tablic np. reduce, map i podobnych:
function sumNumbers() {
const sum = arguments.reduce(function(a, b) { //błąd, reduce jest dla tablic
return a + b;
});
return sum;
}
sumNumbers(1, 2, 3, 4);
W dzisiejszych czasach zamiast operować na obiekcie arguments
, zalecane jest używanie rest operator, który zbiera przekazane argumenty w postaci klasycznej tablicy.
function superSum(...r) {
console.log(r); //[1, 2, 3, 4]
}
superSum(1, 2, 3, 4);
function superSum(...params) {
console.log(params); //[1, 2, 3, 4]
const sum = params.reduce(function(a, b) { //można krócej ale na to przyjdzie jeszcze czas
return a + b;
});
return sum;
}
superSum(1, 2, 3, 4);
Dokładnie na ten temat pomówimy sobie w rozdziale o rest parameter.
Instrukcja return
Każda funkcja zwraca jakąś wartość. Domyślnie jest nią undefined
. Aby zwrócić naszą wartość, posłużymy się instrukcją return
:
function calculate(number1, number2) {
const result = number1 + number2;
return result;
}
calculate(10, 4) //wypisze 14
Dzięki temu, że nasza funkcja zwraca jakąś wartość, możemy ją użyć do innych celów niż tylko wypisywanie tekstów w debuggerze:
function randomBetween(min = 0, max = 10) {
return Math.floor(Math.random()*(max-min+1)+min);
}
//wstawiam wynik do body
document.body.innerText = randomBetween(1, 100);
//wykorzystuję funkcję do powtarzania tekstu
console.log( "kot".repeat(randomBetween(1, 6)) );
//dodaję 2 losowe liczby
console.log( randomBetween(1, 6) + randomBetween(1, 10) );
//generuję tablicę z liczbami 1-100
const tab = [];
for (let i=0; i<10; i++) {
tab.push(randomBetween(1, 100));
}
if (randomBetween(1, 10)) { //w miejscu gdzie używamy funkcji pojawia się wynik
...
}
Instrukcja return nie tylko zwraca wartość, ale i przerywa dalsze działanie danej funkcji.
function sum(a, b) {
return a + b;
console.log(a + b); //nigdy nie zostanie wykonane, bo wcześniej return przerwie działanie funkcji
console.log("Test");
}
W wielu edytorach kod leżący za return będzie miał przytłumione kolory, co symbolizuje, że taki kod nigdy sie nie wykona:

Instrukcji return może być wiele dla jednej funkcji. Zawsze jednak wykonana zostanie tylko jedna:
function getStatus(number) {
if (number < 20) {
return "bad"
}
if (number < 30) {
return "medium"
}
return "good"
}
console.log(getStatus(10));
console.log(getStatus(25));
function fixName(name) {
return name.charAt(0).toUpperCase() + name.slice(1);
}
const result = fixName("piotr") + " " + fixName("kowalski");
console.log(result); //Piotr Kowalski
Instrukcja return może zwracać dowolną wartość. Może to być tablica:
function returnArray(size) {
return new Array(size).fill(0).map((el, key) => key);
}
const result = returnArray(10); //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(result[0]); //0
...lub obiekt:
function returnObject() {
return {
first: "ala",
second: "bala",
third: "cala"
}
}
console.log(returnObject().first); //"ala"
lub inne funkcje, o czym przekonasz się nieco później.
Wyrażenie funkcyjne
Do tej pory poznaliśmy jeden sposób tworzenia funkcji:
function printText() {
...
}
printText();
Jest to tak zwana deklaracja funkcji. Drugi sposób zwie się wyrażeniem funkcyjnym i jest niczym innym jak podstawieniem funkcji pod zmienną:
const printText = function() {
...
}
printText();
Wyrażenie i definicja różnią się od siebie nie tylko sposobem zapisu, ale także tym, jak taki kod jest interpretowany przez przeglądarkę.
Funkcja stworzona za pomocą deklaracji jest od razu dostępna dla całego skryptu. Wynika to z działania mechanizmu hoistingu (znany ze zmiennych), który przenosi taką deklarację na początek danego zakresu kodu (skryptu lub funkcji).
Dzięki temu możemy odwoływać się do funkcji, która jest zadeklarowana poniżej:
myFunction(); //Tutaj jest ok
function myFunction() {
console.log("...");
}
W przypadku wyrażeń funkcyjnych takie odwołanie rzuci nam błędem:
myFunction(); //Błąd
const myFunction = function() {
console.log("...");
}
Wynika to z faktu, że powyżej podstawiliśmy funkcję pod zmienną, a przecież do takich nie możemy się odwoływać przed ich utworzeniem.
Istnieje jeszcze jedna różnica między tymi zapisami. Przy stosowaniu deklaracji, dana funkcja zapisywana jest jako klucz obiektu Window (to samo ma miejsce, gdy tworzymy globalną zmienną za pomocą zmiennej var). W przypadku wyrażenia poprzedzonego słowem const/let nie ma to miejsca.
function testX() {
console.log("x");
}
const textY = function() {
console.log("y");
}
window.testX(); //"x"
window.testY(); //błąd

Powyższe różnice nie oznaczają jednak, że deklaracji nigdy nie powinieneś używać. Używaj - a jakże. W większości przypadków takie detale nie mają totalnie znaczenia.
Funkcja anonimowa
Funkcja anonimowa to taka funkcja, która nie ma swojej nazwy. Funkcje takie wykorzystywane są jako funkcje zwrotne, które przekazujemy do innych funkcji.
document.addEventListener("click", function() {
console.log("klik");
});
[1,2,3].forEach(function(el) {
console.log(el);
});
[1,2,3].sort(function(a, b) {
return a - b;
});
W dzisiejszych czasach powyższe zapisy możemy skrócić za pomocą tak zwanej funkcji strzałkowej. W kolejnym rozdziale zajmiemy się właśnie nią.
Trening czyni mistrza
Jeżeli chcesz sobie potrenować zdobytą wiedzę, zadania znajdują się w repozytorium pod adresem: https://github.com/kartofelek007/zadania