JavaScript в действии: подключение и базовый синтаксис

Раздел: JavaScript -> Работа с JavaScript кодом

Основные способы интеграции JavaScript

Использование JavaScript начинается с выбора способа его подключения к HTML и понимания базовых синтаксических конструкций. Ниже рассмотрены варианты от простого встраивания до современных модулей, а также типичные ошибки.

Наиболее эффективное решение: внешний файл с атрибутом defer

Атрибут defer позволяет загружать скрипт параллельно с парсингом HTML, но выполнять его только после полной загрузки документа. Это не блокирует отображение и гарантирует, что DOM доступен. Порядок выполнения нескольких скриптов с defer сохраняется.

Пример: подключение app.js с defer

<!DOCTYPE html>
<html lang="ru">
<head>
  <script src="app.js" defer></script>
</head>
<body>
  <p id="message">Загрузка...</p>
</body>
</html>

использовать javascript (использование javascript)

// app.js
console.log('Скрипт выполнен после полной загрузки HTML');
document.getElementById('message').textContent = 'JavaScript работает!';
Скрипт выполнен после полной загрузки HTML
(на странице текст изменится на 'JavaScript работает!')

Пояснение: браузер загружает app.js параллельно, но запускает его только после того, как весь HTML разобран. Это исключает ошибки вроде обращения к ещё несуществующим элементам.

Типичные ошибки и их решения:

  • Ошибка: скрипт без defer в <head> блокирует парсинг, страница может отображаться с задержкой. Решение: используйте defer или размещайте скрипт перед закрывающим </body>.
  • Ошибка: document.querySelector возвращает null, если скрипт выполняется до появления элемента в DOM. Решение: оборачивайте код в обработчик DOMContentLoaded или используйте defer.

Как добавить небольшой фрагмент кода прямо в HTML?

Встроенный скрипт (inline) удобен для быстрых тестов или однострочников. Код помещается внутрь тега <script>.

<script>
  console.log('Привет, мир!');
</script>

Проблемы:

  • При большом объёме кода страница становится громоздкой, теряется читаемость.
  • Код не кешируется браузером, что увеличивает объём загрузки при каждом запросе.

Решение:

Для повторного использования или логики объёмом более нескольких строк лучше выносить код во внешний файл.

Как подключить синхронный внешний скрипт, если defer не подходит?

Иногда требуется выполнить скрипт до завершения загрузки страницы (например, для отображения рекламы или аналитики). Тогда атрибут defer не используется, а скрипт помещают в <head> или <body>. Однако это блокирует парсинг.

<head>
  <script src="sync.js"></script>
</head>

Типичная ошибка:

Если скрипт пытается обратиться к элементу, которого ещё нет в DOM, возникает ошибка TypeError: Cannot read properties of null.

Решение:

Перенесите скрипт в конец <body> или используйте DOMContentLoaded внутри самого скрипта, если это возможно.

Async или defer: когда какой выбирать?

Оба атрибута загружаются параллельно, но async выполняет скрипт сразу после загрузки, не дожидаясь остальных скриптов или DOM. defer ждёт окончания парсинга и соблюдает порядок.

<script src="analytics.js" async></script>
<script src="app.js" defer></script>

В этом примере analytics.js может выполниться раньше, чем app.js, даже если он подключён позже. defer гарантирует, что app.js запустится после полной загрузки HTML.

Ошибки:

  • Использование async для скриптов, зависящих от DOM, часто приводит к тем же проблемам с null.
  • Скрипты с async, зависящие друг от друга, могут выполняться в непредсказуемом порядке.

Решение:

Для скриптов, которые работают с DOM или требуют определённого порядка, всегда используйте defer. async подходит для независимых скриптов (счётчики, трекеры).

Расширенные примеры использования JavaScript

1. Модульная архитектура с import/export

Современный JavaScript поддерживает модули (type="module"). Код разбивается на файлы, импортирующие нужные функции. Модули автоматически загружаются с defer-подобным поведением.

Пример
// math.js
export function sum(a, b) {
  return a + b;
}
Пример
// main.js
import { sum } from './math.js';
console.log('Сумма 5 и 3:', sum(5, 3));
Пример
<script type="module" src="main.js"></script>
Сумма 5 и 3: 8

Пояснение: браузер загружает модули параллельно, выполнение происходит после разбора HTML. Модули автоматически находятся в строгом режиме и не загрязняют глобальную область видимости.

2. Динамическая загрузка скрипта через createElement

Иногда скрипт нужно подгрузить только при определённом действии пользователя, например, после клика. Это экономит трафик.

Пример
document.getElementById('loadBtn').addEventListener('click', () => {
  const script = document.createElement('script');
  script.src = 'widget.js';
  script.onload = () => console.log('Виджет загружен');
  document.body.appendChild(script);
});
После клика на кнопку в консоли появляется 'Виджет загружен', когда файл загрузится и выполнится.

Пояснение: динамическое добавление скрипта не блокирует страницу, позволяет отложить тяжёлые библиотеки до момента их реальной необходимости.

3. Асинхронные запросы с async/await и fetch

Для получения данных с сервера без перезагрузки страницы используют fetch в связке с async/await.

Пример
async function loadUsers() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    const users = await response.json();
    console.log('Пользователи:', users);
  } catch (error) {
    console.error('Ошибка загрузки:', error);
  }
}
loadUsers();
Пользователи: [объект пользователя 1, объект пользователя 2, ...]

Пояснение: код ожидает ответа от сервера и затем выводит массив объектов. Блок catch обрабатывает проблемы сети или неверный URL.

4. Работа с замыканиями для создания приватных переменных

Замыкание позволяет сохранять состояние между вызовами функций, не загрязняя глобальную область.

Пример
function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
1
2
3

Пояснение: переменная count доступна только внутри возвращаемой функции - это пример инкапсуляции данных.

5. Деструктуризация и spread оператор для удобной работы с массивами и объектами

Эти приёмы сокращают код и делают его более читаемым.

Пример
// Деструктуризация объекта
const user = { name: 'Анна', age: 25 };
const { name, age } = user;
console.log(name, age); // Анна 25

// Spread оператор для объединения массивов
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1,2,3,4,5,6]

// Копирование объекта с изменением
const updatedUser = { ...user, age: 26 };
console.log(updatedUser); // { name: 'Анна', age: 26 }
Анна 25
[1,2,3,4,5,6]
{ name: 'Анна', age: 26 }

Пояснение: деструктуризация извлекает свойства в отдельные переменные, spread позволяет легко копировать и объединять данные без мутации исходных.

Использование JavaScript - comments

En
использовать javascript (javascript)