«Заменить всё» в JavaScript: от древних костылей до современного стандарта
Представьте ситуацию: вы пишете чат-бота, и пользователь отправил сообщение с опечаткой «привеТТ». Нужно заменить все вхождения «Т» на «т». Или вы парсите CSV-файл и хотите убрать все лишние пробелы. Звучит просто? В JavaScript до недавнего времени это было настоящей головной болью.
Вопрос «How do I replace all occurrences of a string?» — один из самых популярных на Stack Overflow. Тысячи разработчиков спотыкались об эту, казалось бы, элементарную задачу. Почему? Потому что старый добрый replace() по умолчанию заменяет только первое совпадение. Хитрость? Нужно использовать регулярное выражение с флагом g. Но в 2025 году у нас есть гораздо более элегантное решение.
В этой статье мы разберем все актуальные способы заменить все вхождения подстроки в JavaScript: от классики до современных стандартов. Вы узнаете, какой метод выбрать под разные задачи и почему replaceAll — это ваш новый лучший друг.
Почему старый replace() не работает «из коробки»?
Давайте начнем с разочарования, которое постигало каждого новичка:
let text = "Я люблю JavaScript, JavaScript — это круто!";
let newText = text.replace("JavaScript", "Python");
console.log(newText);
// Вывод: "Я люблю Python, JavaScript — это круто!"
Видите? Заменилось только первое вхождение. Метод String.prototype.replace() так спроектирован исторически. Если вы передаете ему строку (а не регулярное выражение), он ищет и заменяет первое совпадение. Для многих языков (Python, Java) это было шоком. Но JavaScript долгое жил с этим ограничением.
Кстати, если вы ищете ответ на вопрос «how do I replace all occurrences of a string in JavaScript» на русском, то знайте — до 2021 года единственным надежным способом было использование RegExp.
Способ №1: Классика — replace() + RegExp (все еще актуален)
Это «дедушкин» метод, который работает во всех браузерах, включая Internet Explorer (да, он еще где-то жив). Секрет — флаг g (global).
let text = "Кошка съела мышку. Кошка довольна.";
let newText = text.replace(/Кошка/g, "Собака");
console.log(newText);
// "Собака съела мышку. Собака довольна."
Плюсы:
- Работает везде (IE11, старые версии Node.js)
- Мощный: можно использовать группы захвата, флаги
i(регистронезависимость) - Очень быстрый
Минусы:
- Нужно экранировать спецсимволы (точка, звездочка и т.д.)
- Код менее читаемый для новичков
- Не подходит, если строка для замены динамическая (приходит от пользователя)
Если вам нужно заменить динамическую строку, используйте конструктор RegExp:
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
let userInput = "привет.мир";
let text = "привет.мир, как дела? привет.мир!";
let safePattern = escapeRegExp(userInput);
let result = text.replace(new RegExp(safePattern, 'g'), 'пока.все');
console.log(result);
// "пока.все, как дела? пока.все!"
Функция escapeRegExp — обязательный ритуал, если вы работаете с пользовательским вводом. Иначе точка в строке будет интерпретироваться как «любой символ».
Способ №2: Современный стандарт — replaceAll() (ES2021+)
Начиная с ES2021 (ECMAScript 2021), у нас есть String.prototype.replaceAll(). Это ответ на вопрос «how do I replace all occurrences of a string in JavaScript», который ждали годы.
let text = "Я люблю JavaScript, JavaScript — это круто!";
let newText = text.replaceAll("JavaScript", "Python");
console.log(newText);
// "Я люблю Python, Python — это круто!"
Вуаля! Никаких регулярных выражений, никаких флагов. Просто и понятно.
Плюсы:
- Максимально читаемый код
- Не нужно экранировать спецсимволы (строка — это строка)
- Работает и с регулярными выражениями (с флагом
g)
Минусы:
- Не поддерживается в старых браузерах (IE, старый Edge)
- Если передать RegExp без флага
g— выбросит исключениеTypeError
// Это вызовет ошибку!
"test".replaceAll(/t/, "x");
// TypeError: String.prototype.replaceAll called with a non-global RegExp argument
Поэтому, если вы используете replaceAll с RegExp, всегда проверяйте флаг g:
let safeRegex = /кот/gi; // флаг g обязателен
let story = "Кот и котенок. Кот спит.";
console.log(story.replaceAll(safeRegex, "пес"));
// "пес и песенок. пес спит."
Способ №3: Разделение и склейка (split + join)
Это хитрый трюк, который используют опытные разработчики. Он не самый производительный, но очень наглядный:
let text = "раз-два-три-раз";
let newText = text.split("раз").join("one");
console.log(newText);
// "one-два-три-one"
Как это работает: split разбивает строку по разделителю на массив, а join склеивает его обратно с новой подстрокой.
Плюсы:
- Работает во всех браузерах (даже в IE3)
- Не нужно думать о спецсимволах
- Интуитивно понятно
Минусы:
- Создает временный массив (лишняя память)
- Медленнее
replaceAllиreplaceна больших строках - Не поддерживает регулярные выражения
Этот метод отлично подходит для простых замен в небольших строках, когда вы пишете код для легаси-систем.
Способ №4: Цикл while (для экзотических случаев)
Иногда вам нужно заменить все вхождения, но с дополнительной логикой на каждом шаге. Например, нумеровать замены или проверять условия. Тут на помощь приходит старый добрый цик