> For the complete documentation index, see [llms.txt](https://shpp.gitbook.io/zero/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shpp.gitbook.io/zero/tutorials/nagadaiki-poyasnyaiki.md).

# Нагадайки-поясняйки

## Escape characters

**`\n`** — перенос рядка

```javascript
console.log("1\n2\n3\n4");
```

**`\t`** — [табуляція](https://uk.wikipedia.org/wiki/%D0%A2%D0%B0%D0%B1%D1%83%D0%BB%D1%8F%D1%86%D1%96%D1%8F) (горизонтальна)

```javascript
console.log("1\t2\t3\t4");
```

**\\** — екранування наступного символа. Екранований символ просто відображається як текст, а не використаний як спеціальна штука з мови програмування. Наприклад:

```javascript
console.log("ці лапки \"заекрановані\", тому все відобразиться");
console.log("ці лапки не "заекрановані", тому буде помилка");

/*
Помилка буде, бо без екрану це перетворюється на 2 окремих рядка 
    "ці лапки не "
та
    ", тому буде помилка"
а між ними - якась незрозуміла для комп'ютера фігня, яка все ламає
*/
```

**Увага**:  `\n`,  `\t` та інші [escape characters](https://en.wikipedia.org/wiki/Escape_character) треба екранувати разом із їх бекслешем:

```javascript
console.log("Перенос рядка")
console.log("екранований: a1\\nb");
console.log("не екранований: a\nb");
console.log("\nТабуляція")
console.log("екранована: a\\tb");
console.log("не екранована: b\tb");
// і т.д. і т.п.
```

Не лякайтесь посилання: крім `\n`,  `\t` та екранованих лапок вам на Zero інші escapes не знадобляться :)

**p.s.** Конкретно лапки можна вставляти в рядки й без екрану, якщо вони різних типів:

```javascript
console.log("одинарні 'в' подвійних");
console.log('подвійні "в" одинарних');
console.log(`а у бектіках 'взагалі' "що'''" завгодно"''чудить" можна :)`);
// https://ru.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D0%B2%D0%B8%D1%81
// це та кнопка, де тільда (~), тільки без Shift (у EN або US розкладках)
```

## Про =, == та ===

{% embed url="<https://uk.csstricks.net/8224659-difference-between-and-in-javascript-examples>" %}

## Літерали

**Літерал** — це "голе" значення. Умовно кажучи: те, що можна покласти до змінної. Наприклад:

```javascript
let n = "222";
n = 100500;

console.log(n + ", " + 12345);
n = true;
```

У цьому прикладі літерали — це:

* &#x20;`"222"`
* `100500`
* `", "`
* `12345`
* `true`

## Скорочення

### Числа

Штуки типу **`i = i + 2`** або **`i = i + "*"`**&#x432;арто скорочувати через **+=.**&#x20;

|        Довго       |     Коротко     |
| :----------------: | :-------------: |
|  **`i = i + 123`** | **`i +=  123`** |
|  **`i = i + "*"`** |  **`i += "*"`** |
| **`i = i + ":)"`** | **`i += ":)"`** |
| **`i = i + "\n"`** | **`i += "\n"`** |
|  **`i = i - 15`**  |  **`i -= 15`**  |
|  **`i = i * -3`**  |  **`i *= -3`**  |
| **`i = i / 7.98`** | **`i /= 7.98`** |

Це працює і зі змінними, і з літералами. Звісно, змінна може називатись не лише **`i`**

**Якщо треба додати / відняти саме одиницю**, є ще коротші форми: інкремент та декремент.

|    Дуже довго   |     Довго    |  Гарнюня  |
| :-------------: | :----------: | :-------: |
| **`i = i + 1`** | **`i += 1`** | **`i++`** |
| **`i = i - 1`** | **`i -= 1`** | **`i--`** |

Увага: **=** в інкременті не треба. Треба просто **`i++`** або **`i--`**: як є, без нічого. Умовно кажучи, у цих спецсимволах **`=`** вже "вшитий під капотом".

Запис типу **`i = i++`** або **`i = i--`** працюватиме, але це неправильно і нівелює саму суть скорочення запису.

Запустіть код та читайте консоль

```javascript
let n = 2; // замість 2 може бути будь-яке число
console.log("Початкове значення: " + n);
console.log("тип n зараз: " + typeof n)

console.put("\n" + n);
n += 27; // те саме, що й n = n + 27
console.log(" += 27 🠖 " + n)

console.put("\n" + n);
n -= 8; // n = n - 8
console.log(" -= 8 🠖 " + n);

console.put("\n" + n);
n *= 3.14; // n = n * 3.14
console.log(" *= 3.14 🠖 " + n);

console.put("\n" + n);
n /= 0.123; // n = n / 0.123
console.log(" /= 0.123 🠖 " + n);


// до речі, += працює ще й для конкатенації (зклеювання рядків)
console.put("\n" + n);
n += "якийсь рядок";
console.log(" += \"якийсь рядок\" 🠖 " + n);

// але після цього, звісно, n сама стане рядком
console.log("\nтип n зараз: " + typeof n)

// тобто:
console.put("\n" + n);
n += 100500;
console.log(" += 100500 🠖 " + n + "\n");

console.put ("від 0, n++: ");
n = 0;
while (n < 10) {
    console.put(n++ + " ");
}

console.put("\nвід 0, ++n: ");
n = 0;
while (n < 10) {
    console.put(++n + " ");
}
```

### boolean

**`!`** — логічне заперечення, логічне "не".&#x20;

```javascript
let n;

// !n — те саме, що "не n", "щось протилежне n"
n = true; // спробуйте змінити це значення, пограйтесь
console.log("n = " + n);
console.log("!n = " + !n);

// !n не змінює вміст змінної
console.log("n все ще = " + n);
// щоб змінити:
n = !n;
console.log("хоба: n = " + n);

// у if, циклах та інших умовах, які зводяться до boolean, можна ще так:

if (n) {
    console.log("if(n) спрацював, n = " + n + " зараз");
}

if (!n) {
    console.log("if(!n) спрацював, n = " + n + " зараз");
}

if (n) {
    console.log("а це IF з if-else, n = " + n + " зараз");
} else {
    console.log("а це ELSE з if-else, n = " + n + " зараз");
}
```

## Тернарний оператор

Тернарний оператор — це коротка (та з парою особливих фіч) заміна `if else` для випадків, коли є лише 2 можливих варіанти розгалуження, а кожна дія може бути записана одним рядком коду.

У звичайного `if else` структура така:

```javascript
if(якщо тут true) {
    то виконай цей код
} else {
    інакше, тобто якщо false, виконай цей код
}
```

А тернарним оператором те ж саме записується так:

```javascript
якщо тут true ? то виконай цей код : інакше, тобто якщо false, виконай цей код
```

Тобто, наприклад

```javascript
let number = 3;
let message;

if (number > 3) {
    message = "number більше 3";
} else {
    message = "number менше або дорівнює 3";
}
```

З тернарником скорочується до

```javascript
let number = 3;
let message = number > 3 ? "number більше 3" : "number менше або дорівнює 3";
```

А якщо звернути увагу, що в обох варіантах початок та кінець повторюються, можна ще коротше:

```javascript
let number = 3;
let message = "number " + (number > 3 ? "більше" : "менше або дорівнює") + " 3";
```

Тут слід пам'ятати, що тернарник, на відміну від `if else` — це окрема незалежна сутність (як масив, наприклад). І тому, якщо треба результат передати до функції, не треба викликати її саму в тернарнику двічі поспіль. Можна сам тернарник передати, як аргумент :wink:&#x20;

Тобто, краще **не** писати так:

```javascript
let number = 3;
number > 3 ? console.log("number більше 3") : console.log("number менше або дорівнює 3");
```

А замість того писати так:

```javascript
let number = 3;
console.log("number " + (number > 3 ? "більше" :" менше або дорівнює") + " 3");
```

### Вкладені тернарники

Як `if else` можуть вкладатись одне в одного, так і тернарники можуть бути вкладеними в інші тернарники.

```javascript
let number = 3;
console.log("number " + (number > 3 ? "більше" : number < 3 ? "менше" : "дорівнює") + " 3");
```

Кількість рівнів вкладеності необмежена.

У цій кракозябрі легко заплутатись, але тернарник у більшості випадків нормально розуміє перенос рядків, тому можна записати якось так:

```javascript
let number = 3;
console.log("number " +
    (number > 3 ? "більше"
        : number < 3 ? "менше"
            : "дорівнює")
    + " 3");
    
// або взагалі так, щоб максимально схоже на if else
console.log("number " +
    (number > 3 
        ? "більше"
        : number < 3 
            ? "менше"
            : "дорівнює")
    + " 3");
```

Це теж далеко не зразок читабельності. Але вже набагато більше схоже на знайомі `if else`. Та одночасно непогано демонструє вкладені один у одного тернарники.

Проте, якщо доводиться щось таке писати, то тернарник майже 100% буде не найкращим рішенням. Тому що він про скорочення, а тут не дуже й коротко; ну а без переносів це не дуже читабельно.

Тож дійте за обставинами, керуйтесь здоровим глуздом і не туліть всюди тернарники замість `if else` без необхідності, а просто тому, що це якась прикольна штука :wink:&#x20;

## Остача від ділення націло (%)

Якщо ви гуглили, що воно таке, то, скоріш за все, натикались на [статтю з Вікіпедії](https://uk.wikipedia.org/wiki/%D0%94%D1%96%D0%BB%D0%B5%D0%BD%D0%BD%D1%8F_%D0%B7_%D0%BE%D1%81%D1%82%D0%B0%D1%87%D0%B5%D1%8E). Якщо зрозуміли - круто. Але якщо той математичний канцелярит не зайшов, є простіше пояснення.

Є `a % b` . Беремо найбільше число, кратне `b`, яке менше або дорівнює `a` . Віднімаємо від `a` це число. Отримана різниця - і є результат. На прикладі `10 % 3`: найближче до `10`, яке можна націло розділити на `3` (тобто кратне `3`) - це `9`. `10 - 9` = `1`. Тобто`10 % 3` буде `1`.  &#x20;

Ось демо-код. Повводьте туди різні числа, в т.ч. від'ємні та не цілі (`6.21` і т.п.). І дивіться, що буде.

```javascript
let number, divider, operatorResult, loopResult;

number = +prompt("Введіть число");
while (typeof number !== "number" || isNaN(number)) {
    number = +prompt("Некоректне число, введіть нормальне");
}

divider = +prompt(`${number} % `);
while (typeof divider !== "number" || isNaN(divider) || divider === 0) {
    divider = +prompt("На це не можна ділити. Спробуйте знову\n" + number + "%");
}

operatorResult = number % divider;
console.log(`${number} % ${divider} => ${operatorResult}\n`);

console.log("Чому так:");
loopResult = Math.abs(number);

if (divider < 0 || number < 0) {
    console.log("Увага! Від'ємні беремо по модулю\n");
    divider = Math.abs(divider);
}

while (divider > 0 && loopResult >= divider) {
    console.log(`${loopResult} - ${divider} = ${loopResult - divider}`);
    loopResult -= divider;
}

console.log(`\nОстача (${loopResult}) менша за дільник (${divider}).`);

if (number < 0) {
    loopResult = -loopResult;
}

console.log(`От вона і є результат: ${loopResult}`);
if (number < 0 && loopResult !== 0) {
    console.log("(вже не по модулю, звісно)");
}
```

Яке у цього практичне застосування? Та дуже просте. Якщо остача `a % b === 0`, то `a` ділиться без остачі на `b`. Тобто `a` кратне `b`. Так, наприклад, можна перевірити число на парність/непарність,  визначивши, чи кратне воно двійці. Або можна дізнатись, скільки мінімум автобусів потрібно для перевозки групи `a` туристів, якщо в кожному автобусі - максимум `b` місць. Або ще щось таке, придумайте самі :)

## Складання у змінну

Інколи (навіть часто), коли в циклах щось виводимо на консоль, замість 100500 разів просто виводити щось на кожній ітерації, корисніше та зручніше — складати значення до змінної (додавати до неї, конкатенувати з нею) а потім один раз виводити саме цю змінну.

Тобто замість

```javascript
for(let i = 0; i < 10; i++) {
    console.put(i);
}
```

якось типу так

```javascript
let buffer = "";
for(let i = 0; i < 10; i++) {
    buffer += i;
}
console.log(buffer);
```

## Приведення типів

### Найчастіші процедури на Zero

```javascript
let n;

console.log()
n = "123"; // рядок
n = +n; // число
n = +"123" // так теж можна

// ЧИСЛО В РЯДОК
n = 123; // це число
n += ""; // будь-що складаємо з рядком — отримуємо рядок
```

### Таблиця конвертацій

Табличка [звідси](https://www.w3schools.com/js/js_type_conversion.asp)

| **Значення** | **Перетворене на число** | **Перетворене на рядок** | **Перетворене на boolean** |
| ------------ | ------------------------ | ------------------------ | -------------------------- |
| false        | 0                        | "false"                  | false                      |
| true         | 1                        | "true"                   | true                       |
| 0            | 0                        | "0"                      | false                      |
| 1            | 1                        | "1"                      | true                       |
| "0"          | 0                        | "0"                      | true                       |
| "000"        | 0                        | "000"                    | true                       |
| "1"          | 1                        | "1"                      | true                       |
| "20"         | 20                       | "20"                     | true                       |
| ""           | 0                        | ""                       | false                      |
| "twenty"     | NaN                      | "twenty"                 | true                       |
| NaN          | NaN                      | "NaN"                    | false                      |
| Infinity     | Infinity                 | "Infinity"               | true                       |
| -Infinity    | -Infinity                | "-Infinity"              | true                       |
| null         | 0                        | "null"                   | false                      |
| undefined    | NaN                      | "undefined"              | false                      |
| \[ ]         | 0                        | ""                       | true                       |
| \[20]        | 20                       | "20"                     | true                       |
| \[10,20]     | NaN                      | "10,20"                  | true                       |

## **Скоуп**&#x20;

Скоуп (область видимості) — це шматок кода всередин&#x456;**`{ }`**

```javascript
for(1) {
    for(2) {
        while(3) {

        }
    }
    for(4) {
        
    }
}
```

Цикли 2, 3 та 4 входять до скоупу 1.\
3 входить до скоупів 1 та 2.\
4 входить до скоупу 1.

І є ще глобальний скоуп, куди входять вони всі разом. Це "нульовий" рівень, тобто ВЕСЬ код в редакторі. Можете уявити, що весь код в IDE загорнутий у верховні невидимі **`{ }`**.

```javascript
{ // це типу умовна "невидима верховна дужка" початку глобального скоупу
for(1) {
    for(2) {
        while(3) {

        }
    }
    for(4) {
        
    }
}
} // а це — верховна дужка кінця. теж умовна і невидима
```

Змінні зі внутрішнього скоупу "бачать" зовнішні. Але із зовнішнього скоупу не видно внутрішні.

```javascript
let n = 100500;
for (let i = 0; i < 10; i++) {
    n++; // так можна, бо ми звертаємось "назовні"
    console.log(i); // так можна, бо i оголошена в цьому ж скоупі
    for(let j = 0; j < 10; j++) {
        console.log(i); // можна, бо теж ідемо в зовнішній скоуп
        console.log(j); // можна
    }
    console.log(j); // а так не можна, буде помилка, бо в цьому скоупі вже нема j
}
```

Тобто правило просте: **назовні — бачимо, всередину — ні.**

## Цикли

**Тіло цикла** — все, що знаходиться всередині цикла `{` тут `}`

```javascript
for() {
    тіло цикла
}

while() {
    тіло цикла
}

do {
    тіло цикла
} while();
```

### Структура циклів

* Якщо треба повторити дії конкретну кількість разів, то юзаємо **for**.
* Якщо вказати кількість повторів заздалегідь неможливо: **while**.
* Якщо треба зробити щось незалежно від обставин як мінімум 1 раз, а далі — по ситуації: **do while**

#### for

```javascript
for(1; 2; 3)
```

`1`: місце для створення однієї або кількох змінних (якщо кілька — через кому)

`2`: вираз або змінна, який цикл конвертує в boolean (див. табличку вище).  Доки `2` буде `true`, цикл повторюватиметься. Якщо стане `false` — цикл перерветься.

`3`: дії, які виконаються в кінці кожної ітерації

```javascript
for (let i = 0, j = 10, k = true; i < 25; i++, j--, k = !k) {
    console.log(`i=${i}\tj=${j}\tk=${k}`)
    if (i > 0 && i % 5 == 0) {
        console.log(":)\n")
    }
}
```

У цьому прикладі:

`1`: `let i = 0, j = 10, k = true`\
`2`: `i < 25`\
`3`: `i++, j--, k = !k`

**Увага**: `1`, `2` та `3` входять в скоуп цикла, в якому вони створені.

#### **while**

Те саме, що `for`, але має лише блок **`2`**. **`1`** Треба руками записувати перед циклом десь ззовні, а **`3`** — в тілі циклу (дляповної тотожності — в самому кінці перед **`}`**.

```javascript
let i = 0, j = 10, k = true;
while (i < 25) {
    console.log(`i=${i}\tj=${j}\tk=${k}`)
    if (i > 0 && i % 5 == 0) {
        console.log(":)\n")
    }
    i++;
    j--;
    k = !k;
}
```

#### do while

```javascript
do {
    X
} while (Y);
```

Що б там не було, бодай 1 раз виконати все, що в `X`. Потім перевірити, чи `Y == true`. Якщо так — повторювати `X` доти, доки `Y == true`

```javascript
let i = 0, j = 10, k = true;
do {
    console.log(`i=${i}\tj=${j}\tk=${k}`)
    if (i > 0 && i % 5 == 0) {
        console.log(":)\n")
    }
    i++;
    j--;
    k = !k;
} while (i < 25);
```

### continue та break

**`continue`**: "ігнорувати весь код в наступних рядках та перейти до наступної ітерації цикла"

**`break`:** "завершити цикл" (точно так же, як якщо б в блоку **`2`** стало **false**)

**Увага**: `continue` та `break` впливають лише на свій скоуп і не чіпають зовнішній. Умовно:

```javascript
for(let i = 0; i < 10; i++) {
    for(let j = 0; j < 10; j++) {
        if (щось) {
            break; // тут перерветься лише j-цикл. А i-цикл продовжиться
        }
        if (ще щось) {
            continue; // перейде до наступної ітерації j, а на i не вплине
        }
    }
}
```

Брейкати зовнішні скоупи [можливо](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label), але це не знадобиться на Zero.

А взагалі варто уникати `continue` та `break`. В тому сенсі, що, якщо можливо без них — робіть без них. Вони не про "**коли** завершити" а "**якщо щось трапилось** — завершити".

Повну різницю між ними зрозумієте на курсі [P2P CS](/zero/arrangements/p2p-cs-entrytest.md).&#x20;

Ну типу, навіщо робити якось так:

```javascript
let i = 0;
while (true) {
    console.log(i);
    if (i == 10) {
        break;
    }
    i++;
}

// або взагалі
for (let i = 0; ; i++) {
    console.log(i);
    if (i == 10) {
        break;
    }
}
```

коли сама [структура циклів](#struktura-cikliv) підштовхує робити так:

```javascript
let i = 0;
while (i <= 10) {
    console.log(i);
    i++;
}

//ну і відповідно
for (let i = 0; i <= 10; i++) {
    console.log(i);
}
```

`break` / `continue` доречні, коли треба **зреагувати на щось, що виникає внаслідок роботи самого циклу**. Наприклад:

```javascript
let inputText;
let counterA = 0;
let counterB = 0;
while (true) {
    counterA++;
    inputText = prompt("Введи щось");

    if (inputText == "пропусти") {
        alert("Ок, на цій ітерації counterB не збільшуємо");
        continue;
    }

    if (inputText == "зупинись") {
        break;
    }

    counterB++;
}

console.log("counterA = " + counterA + "\ncounterB = " + counterB);
```

Коротше кажучи, у більшості випадків, якщо цикл переривається через `break`, а не через умову переривання в голові цикла — з алгоритмом щось не так, і його варто оптимізувати.
