← Назад к вопросам

Изменяем ли String в JavaScript

1.0 Junior🔥 161 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Строки (String) в JavaScript: изменяемость и неизменяемость

Нет, строки в JavaScript НЕЛЬЗЯ изменять. Строки — это неизменяемые (immutable) типы данных. Это одна из фундаментальных характеристик JavaScript и критично понимать для backend-разработчика.

Что означает неизменяемость

Когда вы модифицируете строку, создается новая строка, а исходная остается без изменений:

let str = 'hello';
str = str.toUpperCase(); // Создается НОВАЯ строка 'HELLO'
console.log(str); // 'HELLO'

// Исходная переменная просто переприсвоена, но сама строка 'hello' осталась без изменений

Доказательство неизменяемости

// Пример 1: методы строк не модифицируют оригинал
const original = 'JavaScript';
const modified = original.replace('Java', 'Type');

console.log(original); // 'JavaScript' — не изменилась!
console.log(modified); // 'TypeScript' — новая строка

// Пример 2: попытка прямого изменения
const str = 'hello';
str[0] = 'H'; // Попытка изменить первый символ
console.log(str); // 'hello' — не изменилась!

// Пример 3: методы возвращают новые строки
const s = 'test';
const result = s.concat(' passed'); // Новая строка
console.log(s); // 'test' — не изменилась!
console.log(result); // 'test passed'

Почему строки неизменяемы?

1. Безопасность и предсказуемость

function logUserData(name) {
  console.log('User: ' + name);
  // Если строка изменяется где-то внутри, логирование будет неправильным!
}

const userName = 'Alice';
logUserData(userName);
// Гарантия: 'Alice' не изменится внутри функции

2. Производительность при кэшировании

JavaScript может безопасно кэшировать строки, зная, что они никогда не изменятся:

const str1 = 'javascript';
const str2 = 'javascript';

// Обе переменные могут указывать на ОДИН объект в памяти
console.log(str1 === str2); // true

3. Многопоточность (для backend)

В Node.js, если строка передается в несколько асинхронных операций, не нужно беспокоиться о синхронизации:

const userId = '12345';

// Все параллельные операции получают одну и ту же строку
// Безопасно, так как никто не может изменить эту строку
Promise.all([
  db.query('SELECT * FROM users WHERE id = ?', [userId]),
  cache.set('user:' + userId, data),
  logger.info('User loaded: ' + userId)
]);

Методы строк: все возвращают новые строки

Строковые преобразования:

const str = 'hello world';

// Все эти методы возвращают НОВЫЕ строки
str.toUpperCase();        // 'HELLO WORLD'
str.toLowerCase();        // 'hello world'
str.charAt(0);            // 'h'
str.substring(0, 5);      // 'hello'
str.slice(0, 5);          // 'hello'
str.split(' ');           // ['hello', 'world']
str.replace('world', 'JS'); // 'hello JS'
str.trim();               // удаляет пробелы
str.padStart(20, '*');    // '******* hello world'
str.repeat(2);            // 'hello worldhello world'
str.concat(' forever');   // 'hello world forever'

// Исходная str осталась 'hello world'
console.log(str); // 'hello world'

Практический пример: обработка пользовательского ввода

// Backend: обработка email
function normalizeEmail(email) {
  // Каждый вызов метода возвращает новую строку
  const normalized = email
    .toLowerCase()      // новая строка
    .trim()             // новая строка
    .replace(/\s+/g, ''); // новая строка
  
  return normalized;
}

const userEmail = '  USER@EXAMPLE.COM  ';
const clean = normalizeEmail(userEmail);

console.log(userEmail); // '  USER@EXAMPLE.COM  ' — не изменилась!
console.log(clean);     // 'user@example.com' — новая строка

Различие между String и string в TypeScript

// JavaScript не делает различия, но TypeScript типизирует:
type StringPrimitive = string; // примитив, неизменяем
type StringObject = String;    // объект (редко используется)

const primitive: string = 'hello';
const object: String = new String('hello');

// Примитив — неизменяем
primitive[0] = 'H';
console.log(primitive); // 'hello'

// Объект — можно добавлять свойства (но это плохая практика!)
object.custom = 'property';
console.log(object.custom); // 'property'

Почему это важно для backend-разработчика

1. Обработка логов

const requestId = '123-456-789';
const timestamp = new Date().toISOString();

// Безопасно логировать везде
logger.info('Request: ' + requestId);
db.log('Database call: ' + requestId); // requestId не изменилась
metrics.track('event:' + requestId);   // requestId не изменилась

2. Управление ключами кэша

const cacheKey = 'user:' + userId + ':profile';

// Можно безопасно передавать везде
await redis.get(cacheKey);   // Ключ не изменится
await redis.set(cacheKey, data);
await redis.delete(cacheKey);

3. API контракты

function buildResponse(userId, userName) {
  // Строки, переданные в функцию, не будут изменены
  const response = {
    id: userId,
    name: userName,
    timestamp: new Date().toISOString()
  };
  return response;
}

const id = '12345';
const name = 'Alice';
const result = buildResponse(id, name);
// id и name остались неизменными

4. Асинхронные операции

const token = generateToken();

// Можно безопасно передавать в несколько асинхронных операций
await Promise.all([
  validateToken(token),
  storeToken(token),
  sendNotification('Token: ' + token)
]);

// token гарантированно не изменился

Производительность: String Concatenation

Проблема: каждое объединение создает новую строку

// Неэффективно — создает много временных строк
let result = '';
for (let i = 0; i < 1000; i++) {
  result = result + 'line ' + i + '\n';
  // На каждой итерации создается новая строка!
}

// Лучше: используй Array.join()
const lines = [];
for (let i = 0; i < 1000; i++) {
  lines.push('line ' + i);
}
const result = lines.join('\n'); // одна операция

// Или Template Literals (более читаемо)
const message = `
  Line 1
  Line 2
  Line 3
`.trim();

Сравнение с Arrays (изменяемые)

Для сравнения, массивы ИЗ МЕНЯЕМЫ:

// Строки — неизменяемы
const str = 'hello';
str[0] = 'H';
console.log(str); // 'hello' — не изменилась

// Массивы — изменяемы
const arr = ['h', 'e', 'l', 'l', 'o'];
arr[0] = 'H';
console.log(arr); // ['H', 'e', 'l', 'l', 'o'] — изменилась!

Практический совет

// Когда нужно часто модифицировать строку, используй массив
const words = message.split(' ');
words[0] = words[0].toUpperCase();
words[words.length - 1] = words[words.length - 1] + '!';
const result = words.join(' ');

// Или используй методы строк, которые возвращают новые строки
const result = message
  .split(' ')
  .map((word, i) => i === 0 ? word.toUpperCase() : word)
  .join(' ')
  .concat('!');

Заключение

Строки в JavaScript абсолютно неизменяемы. Это гарантия языка:

  • Никакой метод не изменит исходную строку
  • Все операции со строками возвращают новые строки
  • Это критично для безопасности, производительности и предсказуемости кода

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