(naciśnij spację, żeby kontynuować)
Dziś poznamy lepiej funkcje. Są one bardzo ważną częścią języka JavaScript (i programowania w ogóle).
Jeżeli byłyście na naszym warsztacie, pisałyście tam własne funkcje do obsługi przycisków na stronie.
Funkcje przydają się, gdy chcemy ten sam kawałek kodu wykonać kilka razy.
Można wykonywać go za każdym razem na innych danych.
Funkcja może też zwracać wynik swojego działania, na którym reszta kodu będzie działać dalej.
Te z was, ktore znają pętle, wiedzą że też mogą wykonywać ten sam kod kilka razy...
Pętlę wykonujemy kilka razy jeden po drugim, i na tym koniec. Funkcję możemy wywołać w dowolnym momencie, z dowolnego miejsca w kodzie.
Pętla musi mieć z góry przygotowane dane i działa na nich w ściśle określonej kolejności (0, 1, 2, ...). Funkcja za każdym razem może dostać nowy zestaw danych, niezależny od tego co było wcześniej.
Podział na funkcje sprawia, że kod staje się bardziej przejrzysty, i łatwiej szukać w nim błędów.
Żeby wypisać karteczki w pętli, musimy z góry pamiętać, co na której będzie, w jakiej idą kolejności, i wypisać je wszystkie jedna po drugiej.
Używając funkcji możemy pojedynczo dodawać nowe karteczki, kiedy tylko nam coś wpadnie do głowy - nawet kiedy zajmujemy się właśnie czymś zupełnie innym.
Załóżmy, że chcemy dodać nową karteczkę do tablicy z poprzedniego slajdu. Zastanówmy się razem, jakie czynności będziemy musiały wykonać?
1. Weź samoprzylepną karteczkę.
2. Weź długopis.
3. Napisz na karteczce tekst.
4. Przyklej karteczkę na tablicy.
5. Odłóż długopis (?)
Skąd wiemy, jaki tekst napisać na karteczce?
Funkcja: Dodaj nową karteczkę ( dany_tekst ):
1. Weź samoprzylepną karteczkę.
2. Weź długopis.
3. Napisz na karteczce dany_tekst.
4. Przyklej karteczkę na tablicy.
5. Odłóż długopis (?)
Funkcję w JavaScript deklarujemy przy użyciu słowa function
:
function sum(x, y) {
return x + y;
}
Wartości w nawiasie to są parametry - dane, na których funkcja operuje.
Słowem return
oznaczamy wartość zwracaną przez funkcję, na której możemy operować dalej:
let result = sum(2, 3) // result = 5
Pliki z kodem do pobrania znajdziecie tutaj.
W pliku mamy tablicę korkową z dodaną na niej karteczką.
Naszym zadaniem będzie napisać funkcję, która doda do tablicy nową karteczkę, z dowolnym, podanym przez nas tekstem.
W tym celu możemy wykorzystać dwie napisane już funkcje pomocnicze:
getNote()
- która tworzy nową karteczkę i zwraca ją jako wynik działania,addNoteToBoard( note )
- bierze karteczkę przekazaną jako parametr i dodaje ją do tablicy.Zastanawiacie się pewnie, w jaki sposób napiszemy tekst na karteczce?
Nasza karteczka, jak każdy element dokumentu HTML ma właściwość innerText
. Cokolwiek w niej zapiszemy, stanie się treścią karteczki, np:
element.innerText = 'Kodowanie jest fajne!'
Napiszmy funkcję createNewNote
, która przyjmie jako parametr tekst, pobierze nową karteczkę korzystając z funkcji getNote()
, napisze tekst na karteczce - zapisując go w innerText
, a następnie doda karteczkę do tablicy przy użyciu funkcji addNoteToBoard( note )
.
Powinno nam wyjść coś takiego:
function createNewNote( text ) {
let newNote = getNote();
newNote.innerText = text;
addNoteToBoard( newNote );
}
Przetestujmy teraz tę funkcję w konsoli.
Jak to zrobimy?
createNewNote( "Zaprosić koleżankę na następne warsztaty" );
Jeżeli twoja funkcja nazywa się createNewNote
i działa jak trzeba, powinnaś mieć wygodną opcję dodawania nowych karteczek.
Żeby karteczka nie była pusta, można zaproponować domyślny tekst, który pojawi się tam, kiedy nie przekażemy żadnego parametru.
W tym celu możemy użyć parametrów domyślnych.
Przy deklarowaniu funkcji i jej parametrów możemy podać domyślną wartość po znaku =
. Na przykład:
function setColor( color = 'yellow' ) {
// jeżeli podasz kolor w nawiasie, funkcja użyje tego, który podałaś
// jeżeli nie podasz żadnego, automatycznie ustawi się żółty
}
W funkcji createNewNote
, którą wcześniej napisałaś, dodaj domyślną treść, która ma się pojawić, kiedy nie podamy żadnego tekstu.
function createNewNote( text = "Dokupić więcej żółtych karteczek" ) {
let newNote = getNote();
newNote.innerText = text;
addNoteToBoard( newNote );
}
W JavaScripcie parametrem funkcji może być praktycznie wszystko - włącznie z inną funkcją.
Przydaje się to na przykład, kiedy chcemy powiązać funkcję z jakimś zdarzeniem, na przykład naciśnięciem klawisza.
Albo zapamiętać zadanie do zrobienia na potem, zupełnie jak na żółtej karteczce.
Żeby przekazać funkcję jako parametr podajemy w nawiasach jej nazwę:
function cleanUpSomething () {
// funkcja ktorą chcemy wykonać za minutę
}
setTimeout( cleanUpSomething, 60000 );
// wykonaj funkcję cleanUpSomething za 60 sekund
Możemy też zapisać całą funkcję jako parametr innej funkcji:
setTimeout( function cleanUpSomething () {
// funkcja ktorą chcemy wykonać za minutę
}, 60000 );
// wykonaj funkcję cleanUpSomething za 60 sekund
To czego nie możemy, to podać w nawiasach nazwę funkcji wraz z nawiasami:
function cleanUpSomething ( data = '' ) {
// funkcja ktorą chcemy wykonać za minutę
}
setTimeout( cleanUpSomething(), 60000 );
setTimeout( cleanUpSomething( someData ), 60000 );
// w obu przypadkach funkcja cleanUpSomething wykona nam się od razu
Jeżeli tak zrobimy, funkcja wykona nam się na miejscu zamiast być przekazana dalej.
Otwórzmy teraz plik z drugim zadaniem, exercise2.html
Mamy przed sobą częściowo oprogramowany kalkulator. W tym momencie jeszcze żaden guziczek nie działa - żeby go ożywić, musimy napisać kilka nowych funkcji, i podłączyć je pod odpowiednie guziki.
Zacznijmy od w miarę prostego przypadku. Przycisk C zazwyczaj służy do wyczyszczenia ekranu - zmiany tego, co na nim jest na zero. Zastanówmy się (na razie po polsku) co powinno się wydarzyć, kiedy ktoś wciśnie ten przycisk.
Zobaczmy, co nam wyszło:
Kiedy wciśnięto przycisk C:
1. Zapisz 0 jako aktualny numer,
2. Wyświetl aktualny numer na ekranie.
Do wyświetlenia liczby na ekranie możemy użyć właściwości innerText
, którą poznałyśmy już wcześniej. Tylko jak podpiąć ją do ekranu kalkulatora?
Dowolny element na stronie możemy "zbadać" narzędziami przeglądarki:
A następnie pobrać jego selektor w drzewie po prawej:
Używając tego selektora możemy teraz dobrać się do elementu, używając document.querySelector, np:
document.querySelector('#screen').innerText = "Siemanko!";
Możemy uzupełnić nasz pseudokod o bardziej szczegółowe instrukcje:
Kiedy naciśnięto przycisk C:
1. Zapisz 0 jako aktualny numer,
2. Znajdź element o selektorze '#screen',
3. Podmień jego zawartość na aktualny numer.
W pliku exercise2.html
dodaj nową funkcję o nazwie reset
. Funkcja ta powinna zrobić dwie rzeczy: zapisać 0 w zmiennej currentNumber
, oraz złapać element '#screen'
i podmienić jego zawartość, na to co mamy w tej zmiennej. Pamiętaj, żeby użyć tych samych nazw funkcji i zmiennych, inaczej nasz kod nie będzie współpracował z resztą.
function reset() {
currentNumber = 0;
document.querySelector('#screen').innerText = currentNumber;
}
Przetestujmy, jak to działa w konsoli.
To, czego potrzebujemy teraz to powiązać tę funkcję z akcją, kiedy ktoś naciśnie na przycisk C
Uwaga, będzie dużo nowych rzeczy naraz!
Poznałyśmy tam metodę addEventListener
, która pozwala powiązać funkcję z wydarzeniem na elemencie.
element.addEventListener( wydarzenie, akcja-do-wykonania )
- wykonuje
podaną akcję, gdy z elementem stanie się coś konkretnego.
document.querySelector( '#button' ).addEventListener( 'click',
nazwaMojejFunkcji );
Czyli jak to wszystko razem będzie po polsku?
Dopiszmy brakujące fragmenty pseudokodu:
Funkcja reset:
1. Zapisz 0 jako aktualny numer,
2. Znajdź element o selektorze '#screen',
3. Podmień jego zawartość na aktualny numer.
1. Znajdź element o selektorze '#C',
2. Powiąż wydarzenie 'click' na tym elemencie z funkcją reset.
Powiąż teraz funkcję reset
, którą napisałaś, z przyciskiem C
. Do przycisku możesz odnieść się przy użyciu document.querySelector
. Jeżeli nie jesteś pewna jaki jest selektor elementu, sprawdź w narzędziach przeglądarki. Użyj addEventListener
żeby powiązać kliknięcie na tym przycisku z funkcją reset
.
Tak powinna wyglądać całość:
function reset() {
currentNumber = 0;
document.querySelector('#screen').innerText = currentNumber;
}
document.querySelector('#C').addEventListener( 'click', reset );
Sprawdźmy, jak to teraz działa.
Teraz zajmiemy się oprogramowaniem przycisków od 0 do 9.
Nie będziemy szczegółowo wszystkiego same programować, bo dzieje się tu sporo:
Tym wszystkim zajmuje się gotowa już funkcja numberKeyPressed( number )
, zapisana w pliku calc.js
(w domu możecie sprawdzić, jak ta funkcja działa).
Bierze ona liczbę od 0 do 9 jako parametr, i robi wszystko co potrzeba, żeby w odpowiedni sposob dopisać ją na ekranie.
Naszym zadaniem będzie powiązać funkcję numberKeyPressed
z naciśnięciem kolejnych guziczków. Przykładowo, po wciśnięciu guziczka 1 chcemy wywołać tę funkcję z parametrem 1.
Tradycyjnie, zapiszmy najpierw po polsku, co chcemy, żeby się stało.
1. Znajdź przycisk z numerem 1 (selektor '#number1')
2. Powiąż wydarzenie 'click' na tym elemencie z funkcją numberKeyPressed.
3. Przekaż do tej funkcji parametr 1.
Jest tylko jeden haczyk...
Nie możemy tak po prostu przekazać jako parametr funkcji numberKeyPressed
z własnym parametrem.
Jeżeli zapiszemy to jako numberKeyPressed( 1 )
, funkcja wykona nam się od razu, zamiast powiązać z przyciskiem.
Co z tym zrobimy? Na ratunek przyjdzie nam funkcja anonimowa.
To funkcja, która nie ma swojej nazwy. Wygląda na przykład tak:
function (x, y) {
return x + y;
}
Możemy je przypisać do zmiennej:
let sum = function (x, y) {
return x + y;
}
Ale to wiele nie różni się od funkcji nazwanej:
sum( 2, 3 ) // zwróci 5
Prawdziwy użytek można zrobić z funkcji anonimowych przy przekazywaniu jej jako parametr do innej funkcji, albo przy tworzeniu ich dynamicznie (czytaj: na bieżąco).
function cleanUpSomething ( data = '' ) {
// funkcja ktorą chcemy wykonać za minutę
}
setTimeout( cleanUpSomething( someData ), 60000 );
// funkcja cleanUpSomething wykona nam się od razu
setTimeout( function () {
cleanUpSomething( someData );
}, 60000 );
// funkcja cleanUpSomething wykona się za minutę,
// i będzie miała dostęp do zmiennej someData
Napisz kod, który powiąże przycisk 1 z wywołaniem funkcji numberKeyPressed
z odpowiednim parametrem. Potrzebna ci będzie funkcja anonimowa, żeby móc jej ten parametr przekazać. Tradycyjnie przyda nam się document.querySelector
do złapania elementu, i addEventListener
żeby powiązać kliknięcie na tym przycisku z naszą funkcją.
document.querySelector('#number1').addEventListener( 'click',
function () {
numberKeyPressed( 1 );
});
Działa?
Najlepiej do tego celu będzie użyć pętli.
for (warunek początkowy; warunek trwania pętli; instrukcja przejścia) {
// wykonaj ten kod tak długo jak warunek trwania pętli jest prawdziwy
}
Czyli przy 10 elementach od 0 do 9 będziemy miały:
for (let i=0; i<10; i++) {
// wykonaj ten kod tak długo jak warunek trwania pętli jest prawdziwy
}
Przerób kod z poprzedniego etapu, tak żeby przypisywał wywołanie funkcji numberKeyPressed
z odpowiednim parametrem do każdego z przycisków od 0 do 9. Wykorzystaj w tym celu pętlę, i pamiętaj o użyciu odpowiednich selektorów.
for( let i = 0; i < 10; i++ ) {
document.querySelector('#number' + i).addEventListener( 'click',
function () {
numberKeyPressed( i );
});
}
Jak wyszły testy?
Zostały nam do oprogramowania jeszcze guziczki +
, -
, x
i /
. Zastanówmy się przez chwilę, jaką funkcję pełnią w kalkulatorze (możemy otworzyć standardową aplikację kalkulatora do pomocy).
W momencie, gdy naciśniemy przycisk +
, nie wykonujemy jeszcze operacji dodawania. Kalkulator zapamiętuje wtedy liczbę, jaką do tej pory wpisałyśmy, zapamiętuje, że następną operacją będzie dodawanie, i czeka na drugą liczbę, ktorą należy do niej dodać.
Jeżeli miałyśmy już wcześniej zapamiętaną jakąś operację, to wykona się ona również w momencie naciśnięcia znaku +
. Niekoniecznie musi być to dodawanie - może to być zupełnie inna, zapamiętana wcześniej operacja.
Szczegóły tego, jak zapamiętujemy funkcję i kolejne liczby sobie dzisiaj darujemy - kto chce, może poczytać sobie plik calc.js
w domu.
Dzisiaj skorzystamy z gotowej funkcji scheduleNextOperation( operation )
, ktora przyjmuje jako parametr funkcję operującą na dwóch liczbach, i robi wszystko co trzeba, żeby potem to dodawanie mogło się wykonać.
Na początek napiszemy samą funkcję sum( x, y )
, która przyjmuje 2 liczby i zwraca ich sumę jako wynik.
function sum ( x, y ) {
return x + y;
}
Możemy sprawdzić, czy wszystko dobrze działa w konsoli.
Teraz pozostaje nam oprogramować guziczek +
- jeżeli ktoś go naciśnie, chcemy wywołać funkcję scheduleNextOperation
i przekazać do niej funkcję, którą właśnie napisałyśmy.
Żeby móc przekazać parametr do funkcji, która obsługuje zdarzenie, musimy posłużyć się funkcją anonimową.
Znajdź selektor przycisku +
, i powiąż wydarzenie click
na tym elemencie z wywołaniem funkcji scheduleNextOperation
z funkcją sum
jako parametrem. Użyj w tym celu metody addEventListener
i funkcji anonimowej.
function sum( x, y ) {
return x + y;
}
document.querySelector("#plus").addEventListener( 'click' , function() {
scheduleNextOperation ( sum );
});
Skoro mamy już oprogramowane guziczki z liczbami i znak plus, możemy przetestować jak to wszystko działa :-)
Wszystko działa dobrze? To została nam jeszcze jedna rzecz - zrobić to samo dla przycisków -
, x
i /
.
Na tej samej zasadzie napiszmy funkcję, która wykona nam działanie matematyczne i zapamiętajmy ją na potem po naciśnięciu odpowiedniego przycisku.
Dopisz brakujące funkcje odejmowania, mnożenia i dzielenia, i powiąż każdą z odpowiednim przyciskiem. Uwaga, znak mnożenia w JavaScript to wcale nie jest x
!
function substract( x, y ) {
return x - y;
}
document.querySelector("#minus").addEventListener( 'click' , function() {
scheduleNextOperation ( substract );
});
function multiply( x, y ) {
return x * y;
}
document.querySelector("#multiply").addEventListener( 'click' , function() {
scheduleNextOperation ( multiply );
});
function divide( x, y ) {
return x / y;
}
document.querySelector("#divide").addEventListener( 'click' , function() {
scheduleNextOperation ( divide );
});
To już wszystko, co przygotowaliśmy na dzisiaj. Dzięki za wspólnie spędzony czas i do zobaczenia!