Rozwiązania do zadań: JavaScript od podstaw
Cześć! To jest fragment książki JavaScript od podstaw, która ma pomóc w nauce programowania od zera.
Stringi
W pierwszym przypadku zwróć uwagę na zastosowanie pojedynczych cudzysłowów, aby w środku umieścić podwójne.
console.log('Kim jest "ona"?'); // Kim jest "ona"?
W drugim przypadku nie użyliśmy tej sztuczki, więc podwójny cudzysłów w środku kończy stringa, a następnie otwiera nowy. Na szczęście w środku znajduje się znak +
, który łączy dwa teksty w jeden. Zauważ podwójną spację pomiędzy "Użyję" a "by" w wyświetlonym tekście.
console.log("Użyję "+" by dodać teksty");
// Użyję by dodać teksty
Jeśli chcielibyśmy wypisać "+"
, to powinniśmy otoczyć cały tekst cudzysłowami pojedynczymi.
console.log('Użyję "+" by dodać teksty');
// Użyję "+" by dodać teksty
W ostatnim przypadku popełniliśmy typowy błąd nowicjusza i zapomnieliśmy o użyciu spacji, gdy dodajemy dwa stringi.
console.log("Tekst," + "następny," + "jeszcze jeden");
// Tekst,następny,jeszcze jeden
To, co powinniśmy zrobić, to dodać tę spację albo w tekście po lewej, albo po prawej od znaku dodawania.
console.log("Tekst, " + "następny, " + "jeszcze jeden");
// Tekst, następny, jeszcze jeden
console.log("Tekst," + " następny," + " jeszcze jeden");
// Tekst, następny, jeszcze jeden
JavaScript jako kalkulator
console.log(1 * 2 + 3 * 4 + 5 * 6 + 7 * 8 + 9);
// 109
console.log(1 * (2 + 3) * (4 + 5) * (6 + 7) * (8 + 9));
// 9945
// Różni się od poprzedniego, bo nawiasy wymuszają
// dodawanie przed mnożeniem.
console.log(1 * 2 / 3 * 4 / 5 * 6 / 7 * 8 / 9 * 10);
// 4.063492063492064
// musiało być większe od 1, bo ostatnie jest mnożenie.
console.log(2 ** 10); // 1024
// to bardzo znana liczba w programowaniu
// "kilo" w kontekście informatyki oznacza zwykle 1024,
// w czasie gdy w innych kontekstach oznacza 1000.
JavaScript jako kalkulator porównujący
W pierwszym przypadku mnożenie kończy się na 5, a więc możemy spodziewać się, że prawa strona jest większa. Poniższy kod to potwierdza.
console.log(1 * 2 + 3 * 4 + 5 < 1 + 2 * 3 + 4 * 5);
// true
Poniżej sprawdzamy dla innych przypadków, czy lewa strona jest większa od prawej.
console.log(2 ** 20 > 3 ** 15);
// false, więc prawa strona jest większa
console.log(2 ** 15 > 10 ** 4);
// true, więc lewa strona jest większa
Możemy też sprawdzić na odwrót.
console.log(2 ** 20 < 3 ** 15); // true
console.log(2 ** 15 < 3 ** 4); // false
Definiowanie zmiennych
const constantValue = "1234";
console.log(constantValue); // 1234
let name = "Michał";
//***
console.log(name); // Michał
name = "Marcin";
console.log(name); // Marcin
Nazywanie zmiennych
publicWorkshops
— Poprawna nazwa.1wayTicket
— Nie zaczynamy nazw zmiennych od liczb. Lepsza wersja tooneWayTicket
.arbitraryUser
— W zasadzie poprawne, aczkolwiek pierwsza część jest niepotrzebnie długa. Gdy chcemy wyrazić, że chodzi o jakąś wartość (przydatne przy testach), używamya
luban
. Lepiej byłobyaUser
.noteType
— Poprawna nazwa.userMaciek
— Formalnie akceptowalna, aczkolwiek użycie polskiego imienia jest dyskusyjne. Także zwykle wydzielamy zmienne, by określić coś uniwersalnego — co charakteryzuje tego użytkownika. W pewnych przypadkach taka nazwa byłaby akceptowalna, ale zazwyczaj preferowalibyśmy na przykład:aUser
jak chodzi o "jakiegoś użytkownika",user1
jeśli chodzi o jednego z kilku, czyadminUser
jeśli chodzi o użytkownika będącego adminem.postUserRequest
— Poprawna nazwa. Tutajpost
odnosi się do metody POST w protokole internetowym HTTP.szkolenieWarszawa
— Nie używamy polskich słów przy nazywaniu zmiennych. Lepsza wersja toworkshopWarsaw
.
Dodawanie i odejmowanie od wartości zmiennych
let fruits = "Figa ";
let price = 0;
fruits += "Gruszka ";
price += 3.2;
console.log(fruits); // Figa Gruszka
console.log(price); // 3.2
fruits += "Banan ";
price += 2.8;
console.log(fruits); // Figa Gruszka Banan
console.log(price); // 6
fruits += "(kupon zniżkowy)";
price -= 1.4;
console.log(price); // 4.6
undefined
i null
let name = null;
let surname;
console.log(name); // null
console.log(surname); // undefined
name = surname;
surname = "Michalski";
console.log(name); // undefined
console.log(surname); // Michalski
Warunki
Fragment pierwszy, wariant pierwszy
Cześć Michał
Może coś do picia?
Fragment pierwszy, wariant drugi
Witamy Pana Prezesa
Cześć Prezes Marek
Może coś do picia?
Fragment pierwszy, wariant trzeci
Cześć Paweł
Może czekoladkę?
Fragment pierwszy, wariant czwarty
Może czekoladkę?
Fragment drugi, wariant pierwszy
Cześć Michał
Może coś do picia?
Fragment drugi, wariant drugi
Witamy Pana Prezesa
Może coś do picia?
Fragment drugi, wariant trzeci
Cześć Paweł
Może czekoladkę?
Fragment drugi, wariant czwarty
Cześć
Może czekoladkę?
Fragment trzeci, wariant pierwszy
Cześć Michał
Kategoria: Dorośli
Fragment trzeci, wariant drugi
Witamy Pana Prezesa
Kategoria: Starsi
Fragment trzeci, wariant trzeci
Cześć Paweł
Kategoria: Dzieci
Fragment trzeci, wariant czwarty
Kategoria: Młodzież
Złożone wyrażenia logiczne
const hasComputer = true;
const passedTest = false;
let isGrounded = false;
console.log(hasComputer && passedTest);
// false, ponieważ true && false
console.log(passedTest || isGrounded);
// false, ponieważ false || false
console.log(hasComputer && !passedTest);
// true, ponieważ true && !false
let canPlayGames = hasComputer && !isGrounded;
// true, ponieważ true && !false,
// a więc true && true
console.log(canPlayGames); // true
let playGames = hasComputer && canPlayGames;
// true, ponieważ true && true
if (!passedTest) {
isGrounded = true;
}
console.log(playGames); // true,
// ponieważ gdy wartość ta była obliczana,
// isGrounded był równy false
console.log(passedTest || !isGrounded);
// false, ponieważ false || !true,
// ponieważ aktualna wartość isGrounded to true
console.log(!(!hasComputer || !passedTest));
// false, ponieważ true && false,
// bo !(!a || !b) jest równoznaczne z a && b
Operator warunkowy
- "Ma na imię Jasio" zostanie wypisane dla
name
równego"Jasio"
. Pusty string dlaname
będącego falsy (czylifalse
,null
,undefined
,""
,0
,0n
,NaN
). - "Ma 10 lat" zostanie wypisane dla
age
równego10
, zaśnull
dlaage
będącego falsy. - "Ma na imię Janek" zostanie wypisane dla
name
równego"Janek"
. Dlaname
będącego falsy, wypisana będzie wartośćname
. - Wartość
age
będzie wypisana, gdy jest ona liczbą większą od 0, a w przeciwnym wypadku będzie to 0.
Ciągi matematyczne
Wypisz kolejne liczby parzyste (wielokrotności 2), zaczynając od 0, a mniejsze od 100.
let i = 0;
while (i < 100) {
console.log(i);
i += 2; // albo i = i + 2;
}
Wypisz kolejne wielokrotności 7, zaczynając od 0, a mniejsze od 100.
let i = 0;
while (i < 100) {
console.log(i);
i += 7; // albo i = i + 7;
}
Wyświetl kolejne wartości powstałe w wyniku wielokrotnego potrajania liczby, zaczynając od 13, tak długo, jak długo wynik jest mniejszy niż 1000.
let i = 13;
while (i < 1000) {
console.log(i);
i *= 3; // albo i = i * 3;
}
Wypisz kwadraty kolejnych liczb całkowitych, mniejszych od 1000.
let i = 0;
while (i * i < 1000) {
console.log(i * i);
i += 1; // albo i = i + 1;
}
Przypadki użycia pętli for dla liczb
Wypisz kolejne liczby od 10 do 5.
for (let i = 10; i >= 5; i--) {
console.log(i);
}
Wypisz kolejne liczby od 5 do 30, z pominięciem ostatniej.
for (let i = 5; i < 30; i++) {
console.log(i);
}
Wypisz co drugą liczbę od 20 do 0.
for (let i = 20; i >= 0; i -= 2) {
console.log(i);
}
Funkcje
function printSum(a, b) {
console.log(a + b);
}
function printNumbers(a, b) {
for (let i = a; i <= b; i++) {
console.log(i);
}
}
function printStars(num) {
let stars = "";
for (let i = 0; i < num; i++) {
stars += "*";
}
console.log(stars);
}
function printSquare(size) {
for (let i = 0; i < size; i++) {
printStars(size);
}
}
function printTriangle(size) {
for (let i = 1; i <= size; i++) {
printStars(i);
}
}
Funkcje zwracające wartości
function daysToMillis(days) {
return days * 24 * 60 * 60 * 1000;
}
function triangleArea(a, b) {
return a * b / 2;
}
function biggestOf(a, b, c) {
if (a >= b && a >= c) {
return a;
} else if (b >= c) {
return b;
} else {
return c;
}
}
JavaScript jako kalkulator matematyczny
console.log(4 ** 2 * Math.PI); // 50.26...
console.log(Math.log10(20 * 30 + 40)); // 2.80...
console.log(Math.log2(Math.pow(10, -5))); // -16.60...
// albo
console.log(Math.log2(10 ** -5)); // -16.60...
console.log(Math.abs(Math.pow(-3, 7))); // 2187
// albo
console.log(Math.abs((-3) ** 7)); // 2187
Funkcje jako wartości
speak()
— TylkoMowa...
speak(cheerKids)
—Hej, dzieci
orazMowa...
speak(cheerAll)
—Hej, dzieci
,Witam rodziców
a potemMowa...
speak(cheerAll, bless)
—Hej, dzieci
,Witam rodziców
,Mowa...
i wreszcieZdrowia!
speak(bless)
—Zdrowia!
a potemMowa...
speak(undefined, bless)
—Mowa...
a potemZdrowia!
Obiekty
const user = {
name: "Kuba",
surname: "Wędrowycz",
address: {
country: "Polska",
city: "Stary Majdan",
postal: "22-120",
street: null
}
};
const book = {
title: "Karpie Bijem",
releaseYear: 2019
};
// Użycie
console.log(user.surname); // Wędrowycz
user.name = "Jakub";
console.log(user.address.city); // Stary Majdan
user.address.street = "Bagnowska";
console.log(book.releaseYear); // 2019
releaseYear
nie powinien być oddzielony na osobny obiekt release
, ponieważ nie ma to sensu, gdy nie interesuje nas nic więcej na temat tego wydania. Moglibyśmy tak zrobić, gdyby było (albo gdybyśmy się spodziewali, że będzie) więcej danych na temat wypuszczenia tej książki, na przykład releaseStatus
czy releaseType
.
Zabawa z obiektami
let obj = {};
const obj2 = obj;
obj.name = "Alek";
console.log(obj.name); // Alek
console.log(obj2.name); // Alek
const obj3 = { name: obj.name };
console.log(obj3); // {name: "Alek"}
obj = { size: "S" };
console.log(obj.name); // undefined
console.log(obj.size); // S
console.log(obj2.name); // Alek
JSON
Przykładowa odpowiedź mogłaby wyglądać tak:
{
"name": "Air Max 720",
"brand": "Nike",
"description": "Mają największą...",
"size": 45,
"imageUrl": "https://example.pl/path/to/airmax.png",
"price": {
"value": "649.99",
"currency": "PLN"
}
}
Konto bankowe
function makeBankAccount() {
return {
balance: 0,
deposit: function(amount) {
this.balance += amount;
return this.balance;
},
withdraw: function(amount) {
if(amount > this.balance) {
amount = this.balance;
}
this.balance -= amount;
return amount;
},
currentBalance: function() {
return this.balance;
}
}
}
Krótsza alternatywa:
function makeBankAccount() {
return {
balance: 0,
deposit: function(amount) {
this.balance += amount;
return this.balance;
},
withdraw: function(amount) {
amount = Math.min(amount, this.balance);
this.balance -= amount;
return amount;
},
currentBalance: function() {
return this.balance;
}
}
}
Konto bankowe z operatorem new
function BankAccount() {
this.balance = 0;
this.deposit = function(amount) {
this.balance += amount;
return this.balance;
};
this.withdraw = function(amount) {
amount = Math.min(amount, this.balance);
this.balance -= amount;
return amount;
};
this.currentBalance = function() {
return this.balance;
};
}
Konto bankowe przez definicję klasy
class BankAccount {
constructor() {
this.balance = 0;
}
deposit(amount) {
this.balance += amount;
return this.balance;
}
withdraw(amount) {
amount = Math.min(amount, this.balance);
this.balance -= amount;
return amount;
}
currentBalance() {
return this.balance;
}
}
Tworzenie i modyfikacja tablic
const values = [true, 42, "AAA"];
console.log(values.pop()); // "AAA"
console.log(values.pop()); // 42
values.push(88);
console.log(values); // [true, 88]
const pets = ["dog", "cat"];
pets.pop();
pets.push("pig");
console.log(pets); // ["dog", "pig"]
const pet = pets.pop();
console.log(pets); // ["dog"]
console.log(pet); // "pig"
Wielkość i elementy tablicy
const letters = ['A', 'B', 'C', 'D', 'E', 'F'];
console.log(letters.length); // 6
console.log(letters[4]); // E
const numbers = [5, 6, 7, 8, 9, 10, 11, 12];
console.log(numbers.length); // 8
console.log(numbers[3]); // 8
forEach
function printAllValues(values) {
values.forEach(function (value, index) {
console.log("Na pozycji " + index +
' znajduje się "' + value + '"');
});
}
function sumAll(numbers) {
let sum = 0;
numbers.forEach(function (number) {
sum += number;
});
return sum;
}
map
Przykładowa odpowiedź:
function toFullNames(users) {
return users.map(function (user) {
if(user.secondName) {
return user.firstName + " " + user.secondName +
" " + user.lastName;
} else {
return user.firstName + " " + user.lastName;
}
});
}
Funkcje strzałkowe przy przetwarzaniu kolekcji
const list = students
.filter(s => s.score >= 3.5)
.filter(s => s.points >= 20)
.map(s => s.name + ", " + s.score)
.forEach(str => console.log(str));
Podwójny filtr można zamienić na pojedynczy, a mapowanie przed forEach
jest niepotrzebnym krokiem.
const list = students
.filter(s => s.score >= 3.5 && s.points >= 20)
.forEach(s => console.log(s.name + ", " + s.score));
Funkcje strzałkowe zamiast metod
const times = (a, b) => a * b;
const compareScoresDescending =
(s1, s2) => s2.score — s1.score;
const compareNames = (s1, s2) => {
if(s1.name< s2.name) return -1;
if(s1.name >s2.name) return 1;
return 0;
};
Z funkcji strzałkowych do anonimowych i nazwanych
// 1. Funkcje anonimowe
const triple = function(i) {
return i * 3;
};
const first = function(arr) {
return arr[0];
};
const bigger = function(a, b) {
return a > b ? a : b;
};
// 2. Funkcje nazwane
function triple(i) {
return i * 3;
}
function first(arr) {
return arr[0];
}
function bigger(a, b) {
return a > b ? a : b;
}