Функции: именование и лучшие практики
Хорошо названная функция — самодокументирующийся код: имя должно точно описывать действие, аргументы — данные, return — результат; функция должна делать одно дело и делать его хорошо.
Зачем нужно
Большая часть времени разработчика уходит на чтение кода. Правильно названные функции с чёткими обязанностями делают код понятным без комментариев, упрощают рефакторинг и тестирование. «Как назвать» — один из самых частых вопросов при код-ревью.
Где используется
- Любой JavaScript-код — фронтенд, бэкенд, тесты
- Code review — стандарты именования в команде
- Рефакторинг и поддержка легаси-кода
Соглашения об именовании
// Глагол + существительное — что делает функция
function getUser(id) {}
function fetchProducts() {}
function validateEmail(email) {}
function renderCard(data) {}
function handleSubmit(event) {}
function calculateTotal(items) {}
// Булевы функции — is/has/can/should
function isValid(value) {}
function hasPermission(user, action) {}
function canEdit(user, resource) {}
function shouldRetry(error) {}
// Обработчики событий — on + событие или handle + действие
function onClick() {}
function onUserLogout() {}
function handleSearch(query) {}
// Трансформации — глагол + что
function formatDate(date) {}
function parseJSON(str) {}
function normalizeUser(raw) {}
function mapToViewModel(entity) {}
// Фабрики — create/make/build
function createButton(label) {}
function makeRequest(config) {}
function buildQueryString(params) {}
Принцип единственной ответственности
// Плохо: функция делает слишком много
function processUserData(data) {
// Валидация
if (!data.name) throw new Error('Нет имени');
// Преобразование
data.name = data.name.trim().toLowerCase();
// Сохранение
db.save(data);
// Отправка письма
emailService.send(data.email, 'Добро пожаловать!');
// Логирование
logger.info('User created:', data.id);
}
// Хорошо: разделение на маленькие функции
function validateUser(data) {
if (!data.name?.trim()) throw new ValidationError('Имя обязательно');
if (!isValidEmail(data.email)) throw new ValidationError('Неверный email');
return data;
}
function normalizeUser(data) {
return { ...data, name: data.name.trim().toLowerCase() };
}
async function createUser(rawData) {
const validated = validateUser(rawData);
const normalized = normalizeUser(validated);
const user = await db.users.create(normalized);
await emailService.sendWelcome(user.email);
logger.info('User created:', user.id);
return user;
}
Параметры: не более 3, используй объект
// Плохо: много позиционных параметров
function createRequest(url, method, body, headers, timeout, retries) {}
// Хорошо: объект конфигурации
function createRequest({ url, method = 'GET', body = null, headers = {}, timeout = 5000, retries = 3 }) {}
// Использование
createRequest({ url: '/api/users', method: 'POST', body: { name: 'Иван' } });
Чистые функции (Pure Functions)
// Нечистая: зависит от внешнего состояния, имеет побочные эффекты
let total = 0;
function addToTotal(n) {
total += n; // мутирует внешнее состояние
return total;
}
// Чистая: только аргументы → результат, без побочных эффектов
function add(a, b) { return a + b; }
// Чистая: иммутабельное обновление
function addItem(items, newItem) {
return [...items, newItem]; // не мутирует оригинал
}
Размер функции: правило одного экрана
// Функция должна умещаться на одном экране (~20-40 строк)
// Если длиннее — скорее всего нужно разбить
// Плохо: 100-строчная функция со вложенными условиями
function hugeFunction(data) {
// ... 100 строк ...
}
// Хорошо: основная функция как оркестратор
async function processOrder(orderId) {
const order = await fetchOrder(orderId);
const valid = validateOrder(order);
const enriched = await enrichWithUserData(valid);
const result = await submitOrder(enriched);
await notifyUser(result);
return result;
}
Частые ошибки
1. Аббревиатуры и однобуквенные имена
// Плохо
function calc(u, p, d) {}
function fn(x) {}
// Хорошо
function calculateTotal(user, products, discount) {}
function transform(inputValue) {}
// Исключение: математические формулы, итераторы
for (let i = 0; i < arr.length; i++) {}
const distance = Math.sqrt(x**2 + y**2); // x, y — общепринятые
2. Ложные имена
// getUser — должна только возвращать, не менять
function getUser(id) {
const user = db.find(id);
user.lastAccessed = new Date(); // неожиданный побочный эффект!
return user;
}
// Правильно: разделить или переименовать
function findUser(id) { return db.find(id); }
function touchUser(id) { db.update(id, { lastAccessed: new Date }); }