Avatar ·

Когда нужно использовать escape вместо encodeURI / encodeURIComponent в JavaScript?

Привет! Я недавно начал изучать JavaScript и столкнулся с путаницей при работе с URL-кодированием. В разных примерах кода я вижу три функции: `escape()`, `encodeURI()` и `encodeURIComponent()`. Все они вроде бы делают одно и то же — заменяют специальные символы на их процентное представление, но я не понимаю, когда какую использовать. Например, я пишу небольшой скрипт для отправки данных на сервер через GET-запрос. Мне нужно передать параметры в URL, включая кириллицу, пробелы и знаки препинания. Если я использую `escape()`, то получаю что-то вроде `%u041F%u0440%u0438%D0%B2%D0%B5%D1%82`, а если `encodeURIComponent()` — то `%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82`. Какой вариант правильный? Ещё я слышал, что `escape()` устарел, но его всё ещё используют в старых проектах. Когда вообще стоит его применять? И чем отличается поведение этих функций при работе с разными символами, например, с `&`, `=`, `#` и пробелами? Буду благодарен за подробное объяснение с примерами. ```javascript // Примеры, которые я пробовал const str = "Привет, мир! & test=value#hash"; console.log(escape(str)); console.log(encodeURI(str)); console.log(encodeURIComponent(str)); ``` <<>>

Основные различия между escape, encodeURI и encodeURIComponent

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

1. escape() — устаревшая функция (не используйте!)

Функция escape() была создана в ранних версиях JavaScript и сейчас считается устаревшей (deprecated). Её не следует использовать в современном коде по нескольким причинам:

  • Некорректная обработка Unicode: Для символов с кодами больше 255 (например, кириллица) она использует формат %uXXXX, который не является стандартным для URL-кодирования. Современные браузеры и серверы могут неправильно интерпретировать такие последовательности.
  • Несоответствие стандартам: RFC 3986 (стандарт URL) не поддерживает %uXXXX. Правильный способ — использовать UTF-8 кодировку, как это делают encodeURI и encodeURIComponent.
  • Не кодирует некоторые важные символы: Например, символ @ не кодируется, хотя в некоторых контекстах это может быть проблемой.

Когда использовать: Никогда. Даже если вы видите его в старом коде, замените на encodeURIComponent.

2. encodeURI() — для кодирования целого URL

Эта функция предназначена для кодирования всего URL-адреса (например, https://example.com/путь?query=значение). Она сохраняет синтаксически значимые символы URL:

  • Не кодирует: A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #
  • Кодирует всё остальное, включая пробелы, кириллицу и спецсимволы.

Важно: encodeURI() НЕ кодирует символы #, ?, &, =, потому что они являются частью структуры URL. Это значит, что если вы попытаетесь закодировать параметр запроса, содержащий &, он останется как есть и сломает URL.

3. encodeURIComponent() — для кодирования значений параметров

Это самая безопасная функция для кодирования отдельных компонентов URL (например, значений параметров запроса). Она кодирует все символы, кроме A-Z a-z 0-9 - _ . ! ~ * ' ( ).

  • Кодирует #, ?, &, =, /, :, @ и все остальные.
  • Использует UTF-8 кодировку для Unicode-символов.

Практические примеры

const str = "Привет, мир! & test=value#hash";

// escape() — устарел, выдаёт некорректный результат
console.log(escape(str));
// %u041F%u0440%u0438%D0%B2%D0%B5%D1%82%2C%20%D0%BC%D0%B8%D1%80%21%20%26%20test%3Dvalue%23hash

// encodeURI() — для целого URL, НЕ кодирует &, =, #
console.log(encodeURI(str));
// %D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%2C%20%D0%BC%D0%B8%D1%80!%20&%20test=value#hash

// encodeURIComponent() — для значений параметров, кодирует всё
console.log(encodeURIComponent(str));
// %D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%2C%20%D0%BC%D0%B8%D1%80!%20%26%20test%3Dvalue%23hash

Как правильно применять

Для формирования URL с параметрами:

const baseUrl = "https://example.com/search";
const query = "JavaScript & Node.js";
const category = "программирование";

// Правильно: кодируем каждое значение отдельно
const url = `${baseUrl}?q=${encodeURIComponent(query)}&cat=${encodeURIComponent(category)}`;
console.log(url);
// https://example.com/search?q=JavaScript%20%26%20Node.js&cat=%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5

// Неправильно: encodeURI не закодирует &
console.log(encodeURI(`${baseUrl}?q=${query}&cat=${category}`));
// https://example.com/search?q=JavaScript%20&%20Node.js&cat=программирование
// Здесь & внутри query будет воспринят как разделитель параметров!

Для кодирования якоря (#):

const hashValue = "section 2";
// encodeURIComponent закодирует # как %23
console.log(encodeURIComponent(hashValue)); // section%202

Резюме

  • escape() — не используйте. Только для обратной совместимости с очень старым кодом.
  • encodeURI() — для кодирования всего URL (редко нужно, обычно вы сами собираете URL из частей).
  • encodeURIComponent() — для кодирования значений параметров или любой части URL, которая может содержать спецсимволы. Используйте в 95% случаев.
<<>>

Дополнительные рекомендации и подводные камни

Коллега выше дал исчерпывающий ответ, хочу добавить несколько практических моментов, которые часто вызывают ошибки у новичков.

1. Двойное кодирование

Одна из самых частых ошибок — кодирование уже закодированной строки. Если вы дважды примените encodeURIComponent(), символ % будет преобразован в %25, и данные придут на сервер в искажённом виде.

const str = "hello world";
const encodedOnce = encodeURIComponent(str); // hello%20world
const encodedTwice = encodeURIComponent(encodedOnce); // hello%2520world (ошибка!)

2. Кодирование для разных частей URL

Иногда нужно кодировать не только значения, но и пути. Для пути (path) используйте encodeURI(), но будьте осторожны — он не кодирует /. Если вам нужно закодировать отдельный сегмент пути (например, название документа с пробелами), используйте encodeURIComponent() для каждого сегмента, а затем склейте их.

const folder = "my documents";
const file = "report 2024.pdf";
const path = `/${encodeURIComponent(folder)}/${encodeURIComponent(file)}`;
console.log(path); // /my%20documents/report%202024.pdf

3. Проверка на сервере

Даже если вы всё правильно закодировали на клиенте, сервер может по-разному декоди