> Как реализовать функцию шаблонизатора строки с подстановкой параметров в JavaScript? (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Яндекс

Стек: JavaScript

> Пример ответа

Короткий ответ

Функция шаблонизатора принимает строку с плейсхолдерами вида {{key}} и объект параметров, заменяя плейсхолдеры на соответствующие значения. Реализуется через String.prototype.replace с регулярным выражением и колбэком, либо через split/map. Важно учитывать экранирование, вложенные пути, отсутствующие ключи и производительность при частых вызовах.

Подробное объяснение

Шаблонизатор - это функция, которая заменяет в строке плейсхолдеры на значения из переданного объекта. Базовая реализация использует регулярное выражение для поиска плейсхолдеров и колбэк для подстановки.

Ключевые аспекты:

  • Формат плейсхолдеров: обычно {{key}}, {key} или %key%
  • Обработка отсутствующих ключей: возвращать пустую строку, исходный плейсхолдер или бросать ошибку
  • Вложенные пути: поддержка {{user.name}} через lodash.get или рекурсивный обход
  • Экранирование: возможность вывести {{literal}} без подстановки
  • Производительность: кеширование скомпилированных шаблонов при повторных вызовах

Продвинутые реализации могут поддерживать:

  • Условные блоки ({{#if condition}}...{{/if}})
  • Циклы ({{#each items}}...{{/each}})
  • Фильтры и трансформации значений
  • Частичную компиляцию (precompile)

На практике

В реальных проектах редко пишут шаблонизатор с нуля - используют готовые решения (Handlebars, Mustache, Lodash template). Однако понимание внутреннего устройства важно для:

  • Отладки и оптимизации существующих шаблонов
  • Написания кастомных утилит для специфических форматов (например, генерация SQL или конфигов)
  • Реализации простых интерполяций без лишних зависимостей

Типичный сценарий - форматирование сообщений в UI: t('Hello, {{name}}!', { name: 'John' }).

Пример кода

JAVASCRIPT
function simpleTemplate(str, params) {
return str.replace(/\{\{(.+?)\}\}/g, (match, key) => {
const trimmed = key.trim();
return params[trimmed] !== undefined ? params[trimmed] : match;
});
}
// С поддержкой вложенных ключей
function deepTemplate(str, params) {
const getValue = (obj, path) => {
return path.split('.').reduce((acc, part) =>
acc && acc[part] !== undefined ? acc[part] : undefined, obj);
};
return str.replace(/\{\{(.+?)\}\}/g, (match, key) => {
const value = getValue(params, key.trim());
return value !== undefined ? value : match;
});
}
// С кешированием
const templateCache = new Map();
function cachedTemplate(str, params) {
if (!templateCache.has(str)) {
templateCache.set(str, new Function(
'params',
'return `' + str.replace(/\{\{(.+?)\}\}/g, '${params["$1"]}') + '`'
));
}
return templateCache.get(str)(params);
}

Как отвечать на собеседовании

Начни с простого решения через replace, затем добавь обработку edge cases. Покажи понимание trade-off между простотой и производительностью. Упомяни, что в production используешь готовые библиотеки, но знаешь, как работает под капотом. Если спросят про безопасность - объясни, почему eval/new Function опасны и как их избежать.

Что проверяет интервьюер

  • Владение регулярными выражениями и методами строк
  • Понимание работы замыканий и кеширования
  • Умение проектировать API (какие параметры принимать, что возвращать)
  • Навыки обработки ошибок и краевых случаев
  • Знание, когда стоит использовать готовое решение, а когда писать своё

Типичные ошибки

  • Использование eval или new Function без экранирования (XSS-уязвимость)
  • Игнорирование пробелов внутри плейсхолдеров ({{ name }} vs {{name}})
  • Мутация исходного объекта параметров
  • Отсутствие обработки циклических ссылок в объекте
  • Неправильная обработка специальных символов в значениях (например, $ в replace)
  • Создание нового RegExp при каждом вызове вместо кеширования

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью