Цикли
Проблем
Колко ще спестиш?
Решаваш да спестяваш: първия месец отделяш 10 €, втория 20 €, третия 30 € и все така с по 10 € повече. Колко ще имаш след 4 месеца?
let total = 0;total += 1 * 10;total += 2 * 10;total += 3 * 10;total += 4 * 10;console.log(total);100Работи. Но след 3 години ще са 36 реда, почти еднакви. А ако броят на месеците се въвежда от клавиатурата, изобщо не знаеш колко реда да напишеш. Трябва ти начин да кажеш „повтори това толкова пъти“.
Идеята
for: повтори, докато условието е вярно
Повтарящото се парче код се казва цикъл. Най-често ползваният е for. Ето числата от 1 до 10:
for (let i = 1; i <= 10; i++) { console.log(i);}12345678910В скобите има три части, разделени с ;:
- Начало:
let i = 1. Изпълнява се веднъж, преди всичко останало. Тук се създава броячът. - Условие:
i <= 10. Проверява се преди всеки кръг. Ако е вярно, тялото се изпълнява. Ако не е, цикълът свършва. - Стъпка:
i++. Изпълнява се след всеки кръг.
Всяко изпълнение на тялото се казва итерация или просто кръг.
По-точно, за любопитните
- Стъпката може да е каквато ти трябва:
i += 2(през едно),i--(назад). - Броячът
iсъществува само вътре в цикъла. След затварящата}го няма и ако го ползваш, програмата спира с ReferenceError: i is not defined. - Често ще видиш броене от 0:
for (let i = 0; i < 10; i++). Пак е 10 кръга. Защо се брои от 0, ще стане ясно в урока за масивите.
Виж го
Кръг по кръг
Това са спестяванията от първата карта, с цикъл. Следи как се сменят month и total.
let total = 0;for (let month = 1; month <= 4; month++) { total += month * 10;}console.log(total); // 100Стъпка по стъпка, с думи
- total започва от 0.
- month = 1. Проверка: 1 <= 4 е вярно, влизаме в тялото.
- Кръг 1: total += 1 * 10, total става 10.
- month++ прави month 2. 2 <= 4: още един кръг, total става 30.
- month 3: total става 60.
- month 4: total става 100.
- month++ прави month 5. 5 <= 4 е невярно: цикълът свършва.
- След цикъла total е 100.
Тялото е един ред и е написано веднъж. За 36 месеца сменяш само 4 на 36. А можеш да сложиш там и променлива, прочетена от клавиатурата.
Пробвай
Обратно броене
Какво ще отпечата програмата?
for (let sec = 3; sec > 0; sec--) { console.log(sec);}console.log("Старт!");sec-- намалява брояча след всеки кръг. Когато sec стане 0, условието sec > 0 е невярно и цикълът спира, без да отпечата 0. Редът след цикъла се изпълнява накрая, веднъж.Идеята
while: докато не дойде краят
Понякога не знаеш предварително колко кръга ще има. Касата чете цени, докато касиерът не въведе 0, и тогава казва сметката. Тук for не пасва. Пасва while: само условие, без начало и стъпка.
let total = 0;let price = Number(await ask(""));while (price !== 0) { total += price; price = Number(await ask(""));}console.log(`Общо: ${total} €`);rl.close();12470Общо: 23 €Над кода стоят редовете за ask() от урока „Вход и изход“. Тук не са показани, но трябват, а rl.close() е накрая.
Първата цена се чете преди цикъла, за да има какво да провери условието. Следващата се чете в края на тялото. Ако първото число е 0, тялото не се изпълнява нито веднъж.
Ако искаш тялото да се изпълни поне веднъж, има do-while. Условието е отдолу и се проверява след кръга. Удобно е за въпрос, който се повтаря, докато отговорът не стане приемлив:
let count;do { console.log("Колко билета (от 1 до 10)?"); count = Number(await ask(""));} while (count < 1 || count > 10);console.log(`Запазени билети: ${count}`);rl.close();0153Колко билета (от 1 до 10)?Колко билета (от 1 до 10)?Колко билета (от 1 до 10)?Запазени билети: 3По-точно, за любопитните
- Ако условието никога не стане невярно, цикълът не свършва. Това е безкраен цикъл: програмата „увисва“ и трябва да я спреш ръчно. Най-честата причина е забравена промяна на променливата в условието, например липсващо
price = …в края на тялото. -
След
while (…)на do-while се пише;. JavaScript я слага и сам, ако липсва, но с нея кодът се чете като в Java и C#. - Всеки for може да се напише като while и обратно. Избираш този, който се чете по-ясно:
forза известен брой кръгове,whileза „докато нещо стане“.
Пробвай
Намери грешката
Програмата трябва да събере числата от 1 до 5: 1 + 2 + 3 + 4 + 5 = 15. Отпечатва 10. На кой ред е грешката?
Избери реда с грешката.
С i < n цикълът спира, преди i да стане 5, и 5 не се добавя: 1 + 2 + 3 + 4 = 10. Трябва i <= n.
Такава грешка с един кръг повече или по-малко е най-честата при циклите. Проверката „на сухо“ я хваща: разпиши i и sum за всеки кръг на лист.
Идеята
break и continue
Две думи сменят обичайния ход на цикъла.
continue прескача останалото от текущия кръг и минава на следващия. Записваш часове за прегледи от 9 до 17, но в 13 е обедната почивка:
for (let hour = 9; hour <= 17; hour++) { if (hour === 13) { continue; } console.log(`${hour}:00`);}9:0010:0011:0012:0014:0015:0016:0017:00break спира целия цикъл веднага. Търсиш първото число, на което 91 се дели. Щом го намериш, няма смисъл да продължаваш:
const n = 91;for (let d = 2; d < n; d++) { if (n % d === 0) { console.log(`${n} се дели на ${d}`); break; }}91 се дели на 7По-точно, за любопитните
breakспира само цикъла, в който се намира. Ако е във вложен цикъл (следващата карта), външният продължава.- Често ще срещнеш while (true) с break вътре: цикъл, който свършва не от условието, а от break на подходящото място.
Идеята
Цикъл в цикъл
Залата на киното има 3 реда по 4 места. Искаш да отпечаташ всички места. За всеки ред минаваш през всички места в него:
for (let row = 1; row <= 3; row++) { let line = ""; for (let seat = 1; seat <= 4; seat++) { line += `[${row}-${seat}]`; } console.log(line);}[1-1][1-2][1-3][1-4][2-1][2-2][2-3][2-4][3-1][3-2][3-3][3-4]Това се казва вложени цикли. Вътрешният цикъл минава целия си път при всеки кръг на външния: 3 реда · 4 места = 12 места. console.log винаги слиза на нов ред, затова местата на един ред се събират в текста line, а той се печата след вътрешния цикъл. За всеки ред line започва отначало, празен.
Пробвай
Стълбичка
На първия ред трябва да има една звездичка, на втория две, на четвъртия четири. Какво трябва да пише на празното място?
for (let row = 1; row <= 4; row++) {
let line = "";
for (let star = 1; star <= ; star++) {
line += "*";
}
console.log(line);
}Вътрешният цикъл трябва да се върти толкова пъти, колкото е номерът на реда. Затова границата му е row, броячът на външния цикъл.
Идеята
Случайни числа за игрите
За игра на зарове трябва число, което програмата не знае предварително. Дава го Math.random():
const dice = Math.floor(Math.random() * 6) + 1;console.log(`Хвърли ${dice}`);Math.random() дава дробно число от 0 до 1, без самото 1, например 0.7316…. Умножено по 6, то е от 0 до 6 (без 6). Math.floor маха дробната част и остава цяло число от 0 до 5. С + 1 става от 1 до 6.
Всяко пускане дава различно число, затова тук няма изход. Ето и цикъл, който хвърля, докато не се падне шестица:
let rolls = 0;let dice;do { dice = Math.floor(Math.random() * 6) + 1; rolls++;} while (dice !== 6);console.log(`Шестица след ${rolls} хвърляния`);По-точно, за любопитните
Math.random()не приема начално число:Math.random(42)не обръща внимание на 42. Поредица, която се повтаря при всяко пускане (удобно при тестване), иска отделна библиотека.
- Числата не са истински случайни: смятат се по формула. За игри стигат, за пароли и сигурност не.
Упражнение
Задачи с цикли
Реши задачите в редактора си. За всяка има примерен вход и изход, с който да сравниш своя. Числото се чете както в урока „Вход и изход“.
1. Таблица за умножение. Прочети число и отпечатай произведенията му с числата от 1 до 10.
77 x 1 = 77 x 2 = 147 x 3 = 217 x 4 = 287 x 5 = 357 x 6 = 427 x 7 = 497 x 8 = 567 x 9 = 637 x 10 = 702. Просто число. Едно число е просто, ако се дели само на 1 и на себе си: 2, 3, 5, 7, 11… Прочети число и кажи дали е просто. Подсказка: опитай делителите от 2 нагоре и спри с break при първия.
9191 не е простоЗа 11 изходът е „11 е просто“.
3. Цифрите на число. Прочети цяло положително число. Отпечатай го наобратно и сумата на цифрите му. Подсказка: n % 10 е последната цифра, а Math.trunc(n / 10) маха последната цифра. Повтаряй, докато числото не стане 0.
2024Обратно: 4202Сума на цифрите: 84. Познай числото. Компютърът „намисля“ число от 1 до 100, а ти го търсиш. След всеки опит програмата казва „По-малко е.“ или „По-голямо е.“, а накрая колко опита ти е отнело. Първо го напиши с тайно число 37, за да провериш с примера:
502537По-малко е.По-голямо е.Позна от 3 опита!Когато работи, смени 37 със случайно число от 1 до 100. Вече и ти не знаеш отговора.
Още задачи
- От 1 до N. Прочети N и отпечатай числата от 1 до N на един ред. За 5:
1 2 3 4 5. - Факториел. N! = 1 · 2 · 3 · … · N. За 5: 120.
numberпази цели числа точно само доNumber.MAX_SAFE_INTEGER(9007199254740991), а 20! е по-голямо (2432902008176640000). За големи цели числа JavaScript имаBigInt: число сnнакрая,1n, иBigInt(...)за прочетеното от входа. - Прости числа до N. Отпечатай всички прости числа до N. За 20:
2 3 5 7 11 13 17 19. Проверката от задача 2 отива вътре в цикъл по числата: вложени цикли. - Фибоначи. Всяко число е сумата на предишните две: 0, 1, 1, 2, 3, 5, 8… Прочети N и отпечатай първите N числа. За 10:
0 1 1 2 3 5 8 13 21 34. - Квадрат от звездички. Прочети N и отпечатай квадрат N × N. За 3:
* * ** * ** * *- Триъгълник от звездички. Същото, но на всеки ред толкова звездички, колкото е номерът му. За 3:
** ** * *- Хвърляне на монета. Прочети N, хвърли монета N пъти със случайно число (0 е ези, 1 е тура) и отпечатай колко пъти се е паднало всяко. Колкото по-голямо е N, толкова по-близо са двете числа до N / 2.
- Камък, ножица, хартия. Играч срещу компютър. Играчът въвежда избора си, компютърът избира случайно, програмата казва кой печели. С do-while пита „Още една игра? (да/не)“ и накрая отпечатва резултата.
По-точно, за любопитните
С обикновено number 22! вече не излиза точно, а като приближение:
let result = 1;for (let i = 2; i <= 22; i++) { result *= i;}console.log(result);console.log(Number.MAX_SAFE_INTEGER);1.1240007277776077e+219007199254740991Тест