Функции и замыкания
Стрелочные функции, параметры, функции как значения, замыкания.
Обновлено
Что такое функция
Функция — это именованный блок кода, который вы пишете один раз и запускаете сколько угодно раз. Она получает данные (параметры), что-то с ними делает и, при необходимости, возвращает результат (return).
Представьте рецепт: рецепт (функция) написан один раз; каждый раз, когда вы готовите (вызываете функцию), можно взять другие ингредиенты (аргументы).
function add(a, b) { // a, b = параметры (нужные ингредиенты)
return a + b // результат
}
add(2, 3) // 5 — 2 и 3 = аргументы (конкретные ингредиенты)
add(10, 20) // 30Два разных момента, которые важно различать:
| Определение | Вызов | |
|---|---|---|
| Код | function add(a, b) { ... } |
add(2, 3) |
| Что происходит | JS запоминает рецепт, но не выполняет его | JS выполняет тело функции |
| Сколько раз | один | сколько угодно |
Зачем нужны функции
- Повторное использование — не нужно копировать один и тот же код в 10 мест.
- Имя —
calculateTotal(cart)говорит, что делает; 15 строк вычислений — нет. - Изоляция — переменные внутри функции не смешиваются с остальным кодом.
- Тестирование — маленькую функцию с понятным входом и выходом легко проверить.
Параметры и return
function greet(name = 'аноним') { // значение по умолчанию
return `Привет, ${name}`
}
greet() // 'Привет, аноним'
greet('Ana') // 'Привет, Ana'returnостанавливает функцию и отдаёт результат. Всё после него не выполняется.- Без
returnфункция возвращаетundefined. - Отсутствующие параметры равны
undefined(если у них нет значения по умолчанию).
Rest-параметры и деструктуризация
const total = (...nums) => nums.reduce((s, n) => s + n, 0) // сколько угодно аргументов → массив
total(1, 2, 3) // 6
function createUser({ name, role = 'user' }) { // получаете объект, достаёте поля
return { name, role }
}
createUser({ name: 'Ana' })Больше 3 параметров? Переходите на один объект — порядок больше не важен, а вызов читается сам.
Виды функций
1. Function declaration
function sum(a, b) {
return a + b
}2. Function expression
const sum = function (a, b) {
return a + b
}3. Стрелочная функция
const sum = (a, b) => a + b // неявный return, одно выражение
const square = x => x * x // один параметр — без скобок
const getUser = () => ({ id: 1 }) // возвращаете объект — нужны скобки
const log = msg => { // несколько строк — фигурные скобки + явный return
console.log(msg)
}4. Метод (функция внутри объекта или класса)
const cart = {
items: [],
add(item) { this.items.push(item) },
}5. Асинхронная функция
async function loadUser(id) {
const res = await fetch(`/api/users/${id}`)
return res.json()
}Всегда возвращает Promise — см. Async.
Различия, которые важны
| Declaration | Expression | Стрелочная | Метод | |
|---|---|---|---|---|
| Hoisting — можно вызвать до строки, где она написана | да | нет | нет | — |
Собственный this |
да (зависит от вызова) | да | нет — берёт this снаружи |
да = объект |
arguments |
да | да | нет | да |
Можно вызвать с new |
да | да | нет | нет |
| Неявный return | нет | нет | да (одно выражение) | нет |
Какую использовать и когда
| Ситуация | Выбор |
|---|---|
| главная функция модуля, утилита, React-компонент | declaration (function Card() {}) — читается понятно, есть hoisting |
колбэки: map, filter, onClick, setTimeout, then |
стрелочная — коротко и сохраняет внешний this |
| маленькие функции в переменных, передаваемые как значения | стрелочная |
поведение объекта / класса, использующее this |
метод |
всё, что работает с await |
async (в любой форме) |
| классический function expression | сегодня редко — его заменили стрелочные |
Функции — это значения
В JS функции — объекты первого класса: их можно класть в переменные, передавать аргументами, возвращать из других функций.
const shout = text => text.toUpperCase()
['a', 'b'].map(shout) // передана аргументом → ['A', 'B']
const multiplier = factor => x => x * factor // возвращает функцию
const double = multiplier(2)
double(5) // 10Функция, которая принимает или возвращает функции, называется функцией высшего порядка (map, filter, addEventListener).
Замыкание
Функция помнит переменные того места, где она была создана, даже после того, как это место «закончилось». Это и есть замыкание (closure).
function createCounter() {
let n = 0 // продолжает жить, «замкнутая» в возвращённой функции
return () => ++n
}
const next = createCounter()
next() // 1
next() // 2 — n запомнилась
const other = createCounter()
other() // 1 — каждый вызов создаёт новую nНа замыканиях построены useState, обработчики событий в React, debounce, модули.
Чистые функции
Функция чистая, если:
- при одинаковом входе она всегда даёт одинаковый результат;
- у неё нет побочных эффектов (не меняет внешние переменные, не делает запросов, не пишет в DOM).
const withVat = price => price * 1.2 // ✓ чистая
let total = 0
const addToTotal = price => { total += price } // ✗ меняет что-то снаружиReact-компоненты должны быть чистыми. Бизнес-логика — тоже: её тривиально тестировать.
Частые ошибки
- Забыли
return(особенно в функциях с фигурными скобками) →undefined. - Стрелочная функция возвращает объект без скобок:
() => { id: 1 }возвращаетundefined. - Вызов вместо передачи:
onClick={save()}выполняется сразу; правильноonClick={save}илиonClick={() => save(id)}.
Коротко
- Функция = именованный код, определяется один раз, вызывается сколько угодно; параметры → return.
- Declaration — для главных функций, стрелочные — для колбэков, методы — для объектов.
- Функции — это значения; замыкание = функция помнит, где была создана.