Skip to content

Latest commit

 

History

History
505 lines (344 loc) · 34.8 KB

File metadata and controls

505 lines (344 loc) · 34.8 KB

Урок 16. Введение в JS: подключение скриптов, консоль, let/const/var, типы данных, операторы, if/тернарник

От статики к интерактивности

Все 15 уроков позади дали нам страницу, которая выглядит хорошо и даже умеет отправлять формы — но делает это единственным доступным браузеру нативным способом: полной перезагрузкой. Кнопка "избранное" из Урока 14 визуально существует, но физически ничего не делает при клике. Форма поста из Урока 15 умеет уйти на сервер, но только ценой перезагрузки всей страницы, да ещё и в формате, который не понимает наш JSON-based FastAPI-бэкенд.

JavaScript — это язык, который решает именно эту проблему: он даёт странице поведение, а не только внешний вид. Он умеет реагировать на клики, менять содержимое страницы без перезагрузки, обмениваться данными с сервером в фоне.

Важная оговорка на старте всего модуля. Мы не будем стремиться к экспертному владению JavaScript — вы уже прошли солидный путь в Python, и цель этого модуля не сделать вас профессиональными JS-разработчиками, а дать рабочее понимание логики и инструментов языка ровно в том объёме, который нужен бэкенд-разработчику, чтобы уверенно читать и писать простой фронтенд-код: формы, динамические карточки, запросы к API. Мы будем часто опираться на то, что вы уже знаете из Python — многие концепции (переменные, типы, условия, функции) устроены очень похоже, различия чаще в синтаксисе и деталях, чем в самой логике.


Как подключить JavaScript к странице

Встроенный скрипт (inline)

<script>
  console.log('Привет из встроенного скрипта!');
</script>

Код прямо внутри тега <script>. Работает, но плохо масштабируется — как только скрипта становится больше пары строк, его неудобно поддерживать вперемешку с HTML.

Внешний файл

<script src="script.js"></script>
// script.js
console.log('Привет из внешнего файла!');

Это основной способ подключения JS в реальных проектах — точно так же, как вы подключаете style.css отдельным файлом, а не пишете все стили через style="..." внутри тегов.

Куда помещать <script> — и почему это важно

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8" />
  <title>Моя страница</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <h1>Привет!</h1>
  <p>Какой-то контент страницы</p>

  <!-- Скрипт — в самом конце body -->
  <script src="script.js"></script>
</body>
</html>

Браузер читает HTML сверху вниз, последовательно. Если поместить <script> в <head> без дополнительных атрибутов, браузер остановит чтение и разбор страницы, скачает и выполнит скрипт, и только потом продолжит строить саму страницу — если скрипт пытается найти на странице элемент, которого физически ещё не существует (потому что браузер до него ещё не дочитал), скрипт получит ошибку.

Поэтому классическое и самое надёжное учебное правило — помещать <script> в самый конец <body>, после всего остального содержимого: к этому моменту вся структура страницы уже прочитана браузером и полностью доступна для JavaScript.

Забегая вперёд: у тега <script> есть атрибуты defer и async, которые позволяют разместить скрипт в <head>, но при этом не блокировать построение страницы. Мы вернёмся к ним чуть позже, в уроке про DOM — там будет понятнее, зачем они нужны на практике. Пока используем самый простой и надёжный вариант — конец <body>.


Консоль разработчика — ваш главный инструмент отладки

console.log(...) — способ вывести значение в консоль браузера, специальную панель инструментов разработчика, не показывающую ничего пользователю на самой странице. Это основной инструмент проверки того, что происходит в коде во время его выполнения — аналог print() в Python, который вы уже хорошо знаете.

console.log('Просто текст');
console.log('Значение переменной:', 42);
console.log('Несколько значений через запятую:', 'строка', 123, true);

Открыть консоль можно через инструменты разработчика браузера (обычно клавиша F12 или правый клик на странице → "Просмотреть код" / "Inspect" → вкладка "Console").

Кроме console.log, есть и другие полезные методы:

console.warn('Предупреждение — выделяется жёлтым');
console.error('Ошибка — выделяется красным');
console.table([{ name: 'Матрица', year: 1999 }, { name: 'Начало', year: 2010 }]); // выводит массив объектов как таблицу

console.table особенно удобен для просмотра массивов объектов — то, с чем мы будем много работать при выводе данных, полученных с сервера.


Переменные: let, const, var

В JavaScript, в отличие от Python, переменная объявляется через одно из трёх ключевых слов — и выбор между ними не формальность, а значимое решение.

let — переменная, которую можно переприсвоить

let age = 25;
console.log(age); // 25

age = 26; // переприсвоение — допустимо
console.log(age); // 26

const — переменная, которую нельзя переприсвоить

const name = 'Мария';
console.log(name); // Мария

name = 'Анна'; // TypeError: Assignment to constant variable.

Важная тонкость: const запрещает переприсвоение самой переменной, но не запрещает изменение содержимого объекта или массива, если именно они хранятся в этой переменной:

const user = { name: 'Мария', age: 25 };

user.age = 26; // Допустимо — мы не переприсваиваем саму переменную user,
               // а изменяем свойство объекта, на который она ссылается
console.log(user); // { name: 'Мария', age: 26 }

user = { name: 'Анна' }; // TypeError — а вот это уже переприсвоение самой переменной

Это прямая аналогия с тем, что вы уже видели в Python: const — это не "неизменяемое значение" (как frozen=True в dataclass из ООП-курса), а "неизменяемая ссылка на значение". Списки и словари в Python точно так же можно изменять изнутри, даже если сама переменная больше не переприсваивается.

var — устаревший способ, который вы увидите в старом коде

var count = 10;
count = 20; // допустимо, как и let

Внешне var очень похож на let, но у него принципиально другая, менее предсказуемая область видимости (мы подробно разберём это различие в отдельном уроке про области видимости — забегать вперёд пока не будем). Практическое правило для этого курса: var мы не используем в новом коде, но обязательно узнаём его при чтении чужих (особенно старых) примеров и статей в интернете — он остаётся частью языка и до сих пор часто встречается.

Правило выбора в этом курсе

  • По умолчанию — const. Если значение переменной не должно переприсваиваться дальше по коду — используйте const, это делает код понятнее для того, кто его читает: сразу видно, какие переменные "устойчивы", а какие могут поменяться.
  • Если переменную придётся переприсваивать (счётчик, накопитель, значение, которое меняется в цикле) — let.
  • var — не используем.

Типы данных

JavaScript, как и Python, — язык с динамической типизацией: тип переменной не объявляется заранее, а определяется тем значением, которое ей присвоено, и может меняться при переприсвоении.

Примитивные типы

const age = 25;              // number — и целые, и дробные числа одного типа
const price = 99.90;         // тоже number

const name = 'Мария';        // string
const greeting = "Привет";   // string — одинарные и двойные кавычки равнозначны

const isActive = true;       // boolean
const isDeleted = false;     // boolean

let middleName;               // undefined — переменная объявлена, но значение не присвоено
console.log(middleName);      // undefined

const noValue = null;         // null — намеренное отсутствие значения

Ключевое отличие от Python: в JavaScript нет отдельного типа для целых и дробных чисел — и 25, и 99.90 относятся к единому типу number. В Python, напомним, int и float — разные типы.

undefined vs null — в чём разница

Это частый источник путаницы у новичков:

  • undefined — значение, которое JavaScript присваивает сам, когда переменная объявлена, но ей ничего не присвоено, либо когда функция ничего не возвращает, либо когда обращаются к несуществующему свойству объекта.
  • null — значение, которое разработчик присваивает осознанно, чтобы явно показать "здесь намеренно нет значения".
let unset;
console.log(unset); // undefined — переменная объявлена, но значения ей не давали

let empty = null;
console.log(empty); // null — мы сами явно сказали "здесь пусто"

Оператор typeof — узнать тип значения

console.log(typeof 42);          // "number"
console.log(typeof 'привет');    // "string"
console.log(typeof true);        // "boolean"
console.log(typeof undefined);   // "undefined"
console.log(typeof null);        // "object" — историческая ошибка языка, которая осталась навсегда;
                                  // null — не объект по сути, но typeof исторически возвращает именно так
console.log(typeof {});          // "object"
console.log(typeof []);          // "object" — массивы в JS тоже технически объекты, подробнее — в следующем уроке

Составные типы — краткий анонс

Помимо примитивов, есть object (объекты — аналог словарей Python) и array (массивы — аналог списков Python). Мы подробно разберём их в следующем уроке — сегодня закладываем только словарь терминов, чтобы не путаться при встрече с ними в примерах ниже.

Шаблонные строки (template literals)

Прежде чем перейти к операторам, познакомимся с удобным способом собирать строки — он пригодится нам уже в этом уроке:

const name = 'Мария';
const age = 25;

// Старый способ — конкатенация через +
const message1 = 'Привет, ' + name + '! Тебе ' + age + ' лет.';

// Современный способ — шаблонная строка (обратные кавычки ` `, не обычные кавычки!)
const message2 = `Привет, ${name}! Тебе ${age} лет.`;

console.log(message1); // Привет, Мария! Тебе 25 лет.
console.log(message2); // Привет, Мария! Тебе 25 лет. — тот же результат, но код читается легче

Обратите внимание на символ обратной кавычки (`, backtick) — не путайте его с обычной одинарной кавычкой ('). Внутри ${...} можно поместить любое JS-выражение, не только переменную:

const price = 100;
console.log(`Итого с наценкой: ${price * 1.2}`); // Итого с наценкой: 120

Это прямой аналог f-строк в Python (f"Привет, {name}!") — та же идея, немного другой синтаксис.


Операторы

Арифметические

console.log(10 + 3);  // 13
console.log(10 - 3);  // 7
console.log(10 * 3);  // 30
console.log(10 / 3);  // 3.3333333333333335
console.log(10 % 3);  // 1  — остаток от деления, как и в Python
console.log(10 ** 2); // 100 — возведение в степень (аналог ** в Python)

Сравнения — критически важное различие == и ===

console.log(5 == '5');   // true  — сравнивает значения, ПРИВОДЯ типы друг к другу
console.log(5 === '5');  // false — сравнивает и значение, И тип, без приведения

console.log(0 == false);  // true  — приведение типов срабатывает и здесь
console.log(0 === false); // false — разные типы (number и boolean)

== называется нестрогим сравнением — перед сравнением JavaScript пытается привести оба значения к одному типу, что часто приводит к неожиданным результатам. === — строгое сравнение — сравнивает и значение, и тип, без каких-либо преобразований.

Правило этого курса: всегда используйте === и !==, никогда не используйте == и !=. Это одна из самых частых рекомендаций в профессиональном JavaScript-сообществе — нестрогое сравнение считается источником труднообнаруживаемых ошибок, и почти все современные линтеры (инструменты проверки кода) предупреждают о его использовании.

console.log(5 !== '5');  // true  — используем это
console.log(5 != '5');   // false — а вот так лучше не писать

Остальные операторы сравнения работают предсказуемо и без сюрпризов:

console.log(10 > 5);   // true
console.log(10 < 5);   // false
console.log(10 >= 10); // true
console.log(10 <= 9);  // false

Логические

console.log(true && false); // false — И: оба должны быть true
console.log(true || false); // true  — ИЛИ: достаточно одного true
console.log(!true);         // false — НЕ: инвертирует значение

Синтаксически идентично Python, кроме самих ключевых слов — вместо and/or/not в JS используются &&/||/!.

Присваивание

let count = 10;

count += 5;  // то же, что count = count + 5
count -= 2;  // count = count - 2
count *= 2;  // count = count * 2
count /= 4;  // count = count / 4

console.log(count); // 6.5

Инкремент/декремент

let i = 0;
i++; // i = i + 1
i--; // i = i - 1
console.log(i); // 0 — вернулись к исходному значению

Такого сокращения нет в Python (i++ там вызовет синтаксическую ошибку) — это одно из синтаксических различий языков при похожей общей логике.


Условия: if / else if / else

const age = 20;

if (age < 18) {
  console.log('Несовершеннолетний');
} else if (age < 65) {
  console.log('Взрослый');
} else {
  console.log('Пенсионный возраст');
}

Синтаксис почти идентичен Python по логике, но с важными синтаксическими отличиями:

  • условие обязательно в круглых скобках: if (условие), а не if условие:;
  • тело блока — в фигурных скобках { }, а не через отступ и двоеточие;
  • else if пишется двумя словами через пробел (в Python — elif одним словом).

Тернарный оператор — сокращённая запись if/else

const age = 20;
const status = age >= 18 ? 'Взрослый' : 'Несовершеннолетний';
console.log(status); // Взрослый

Синтаксис: условие ? значение_если_true : значение_если_false. Это выражение, то есть оно возвращает значение — его удобно сразу присваивать переменной, в отличие от полноценного if/else, который управляет потоком выполнения, а не возвращает результат напрямую.

Прямой аналог из Python, который вы уже видели в ООП-курсе: 'Взрослый' if age >= 18 else 'Несовершеннолетний' — та же идея тернарного выражения, другой порядок частей и другой синтаксис.

Когда использовать тернарник, а когда — полноценный if/else: тернарный оператор хорош для простого выбора одного из двух значений в одну строку. Если внутри веток нужно выполнить несколько действий (не просто вернуть значение, а, например, вывести несколько сообщений в консоль или сделать несколько присваиваний) — используйте полноценный if/else, тернарник для этого плохо читается.

// ✅ Хорошо для тернарника — простой выбор значения
const label = isActive ? 'Активен' : 'Неактивен';

// ❌ Плохо — тернарник для нескольких действий читается плохо
isActive ? (console.log('Активен'), doSomething()) : console.log('Неактивен');

// ✅ Здесь однозначно лучше полноценный if/else
if (isActive) {
  console.log('Активен');
  doSomething();
} else {
  console.log('Неактивен');
}

Практика: простой скрипт без DOM — определение возрастного рейтинга фильма

DOM (работу с самой страницой) мы ещё не проходили — это тема отдельного урока. Но уже сейчас, только на переменных, типах и условиях, можно написать полезный самостоятельный скрипт. Воспользуемся prompt() — встроенной функцией браузера, показывающей всплывающее окно с полем ввода, и alert() — всплывающим окном с сообщением. Оба метода не требуют знания DOM и отлично подходят для первой самостоятельной практики.

// age-rating.js

const ageInput = prompt('Введите возраст зрителя:');
const age = Number(ageInput); // Number(...) — преобразование строки в число,
                                // ведь prompt() всегда возвращает строку

let rating;

if (age < 6) {
  rating = 'Просмотр не рекомендован';
} else if (age < 12) {
  rating = '6+';
} else if (age < 16) {
  rating = '12+';
} else if (age < 18) {
  rating = '16+';
} else {
  rating = '18+';
}

console.log(`Возраст: ${age}, рекомендованный рейтинг: ${rating}`);
alert(`Для вашего возраста доступны фильмы с рейтингом ${rating}`);

Разбор: prompt() всегда возвращает строку, даже если пользователь ввёл число — поэтому её обязательно нужно преобразовать через Number(...), иначе сравнения вроде age < 18 могут работать не так, как ожидается (сравнение строк устроено иначе, чем сравнение чисел). Это тот же принцип, что вы уже видели в Python при работе с input() — там тоже пользовательский ввод всегда приходит строкой, и её нужно осознанно преобразовывать через int()/float().


Подводные камни

== вместо ===

console.log('' == 0);        // true  — пустая строка и число 0 считаются "равными" при нестрогом сравнении
console.log(null == undefined); // true — тоже неожиданно для новичка
console.log('' === 0);       // false — строгое сравнение честно говорит: разные типы, не равны

Это одна из самых частых причин труднообъяснимых багов у новичков в JS. Правило простое: используйте ===/!== всегда, без исключений, пока у вас нет очень конкретной, осознанной причины поступить иначе (такие причины в реальной практике есть, но встречаются редко и не относятся к базовому уровню этого курса).

Попытка изменить const

const total = 100;
total = 200; // TypeError: Assignment to constant variable.

Если переменная предполагает переприсваивание — сразу объявляйте её через let, а не начинайте с const "на всякий случай" и не переключайтесь на let только после первой ошибки.

Забытое преобразование типа после prompt()

const input = prompt('Введите возраст:');
console.log(input + 1); // если ввели "20", получится "201" — строка "20" плюс число 1 склеились в строку!

prompt() всегда возвращает строку. Оператор + между строкой и числом в JavaScript не складывает числа, а склеивает их как текст (конкатенация). Всегда преобразуйте пользовательский ввод через Number(...), если планируете арифметику, а не склеивание текста.

Путаница между null и undefined

let value; // undefined — так решил сам JavaScript, мы ничего не присваивали

function getUser() {
  // если явно не написать return — функция вернёт undefined
}

let user = null; // null — мы сами явно так решили

Смысловое правило: undefined — это "значения нет, потому что о нём ещё не позаботились" (побочный эффект языка), null — это "значения нет, и это осознанное решение разработчика". На практике в собственном коде чаще осознанно используют null, а undefined встречается как результат работы самого языка (необъявленная переменная, отсутствующее свойство объекта, функция без return).


Итоги урока

JavaScript подключается к странице через <script> — встроенным блоком или внешним файлом, который принято размещать в конце <body>, чтобы скрипт выполнялся уже после того, как браузер построил всю структуру страницы. console.log() — основной инструмент отладки, аналог print() из Python, результат которого виден в консоли разработчика, а не на самой странице.

Переменные объявляются через const (по умолчанию, если значение не будет переприсвоено), let (если переприсваивание планируется) — var в новом коде не используем, хотя обязательно узнаём его при чтении чужого кода. const запрещает переприсвоение самой переменной, но не запрещает изменение содержимого объекта или массива внутри неё.

Примитивные типы — number (единый тип для целых и дробных чисел, в отличие от Python), string, boolean, undefined (отсутствие значения "по умолчанию" от языка) и null (осознанное отсутствие значения). Строгое сравнение ===/!== предпочтительно всегда — нестрогое ==/!= приводит типы друг к другу неочевидным образом и считается источником багов.

if/else if/else работает по той же логике, что и в Python, но с другим синтаксисом (скобки вместо двоеточий и отступов). Тернарный оператор условие ? значение1 : значение2 — компактная альтернатива для простого выбора одного из двух значений.

В следующем уроке перейдём к циклам (for, while) и функциям — обычным, через function, и стрелочным.


Вопросы для проверки

  1. Почему <script> принято размещать в конце <body>, а не в <head>?
  2. В чём разница между let и const? Приведите пример, когда const-переменная всё же может "измениться".
  3. Почему в этом курсе рекомендуется не использовать var в новом коде, но при этом важно его знать?
  4. В чём разница между undefined и null? Кто их обычно присваивает — сам язык или разработчик?
  5. Почему в этом курсе рекомендуется всегда использовать ===/!== вместо ==/!=?
  6. Что вернёт prompt() и почему после его вызова часто требуется дополнительное преобразование типа?
  7. Когда лучше использовать тернарный оператор, а когда — полноценный if/else?

Практические задания

Задание 1. Информация о фильме через консоль

Напишите скрипт, который объявляет переменные о фильме (title, year, rating, isAvailable) с подходящими типами данных (const, где значения не должны меняться), и выводит в консоль через шаблонную строку (template literal) одно объединённое сообщение вида:

Фильм «Матрица» (1999), рейтинг 8.7. Доступен для просмотра: да

Используйте тернарный оператор для преобразования true/false в "да"/"нет".


Задание 2. Проверка возраста для просмотра (используя prompt)

Напишите скрипт, который:

  1. Запрашивает у пользователя возраст через prompt().
  2. Преобразует введённое значение в число.
  3. Если возраст меньше 18 — выводит через alert() сообщение "Фильм с рейтингом 18+ недоступен".
  4. Если возраст 18 или больше — выводит через alert() сообщение "Приятного просмотра!".
  5. Дополнительно выводит в консоль отладочное сообщение с исходной строкой из prompt() и преобразованным числом, чтобы наглядно увидеть разницу типов.

Задание 3. Калькулятор скидки на билет (объединяющая практика: типы + операторы + условия)

Напишите скрипт кинотеатра, который вычисляет итоговую цену билета:

  1. Базовая цена билета — const basePrice = 400; (рублей).
  2. Через prompt() запросите возраст зрителя, преобразуйте в число.
  3. Правила скидки:
    • Возраст до 12 лет (не включая 12) — скидка 50%.
    • Возраст от 12 до 18 (не включая 18) — скидка 20%.
    • Возраст 60 и старше — скидка 30%.
    • Остальные — без скидки.
  4. Выведите в консоль через шаблонную строку итоговую цену и процент скидки.
  5. Используйте ===/!== там, где нужно строгое сравнение, и не используйте ==/!= нигде в решении.

Предыдущий урок | Следующий урок