Объекты библиотеки Moment.js являются изменяемыми. Это означает, что большинство методов не создают новый экземпляр даты, а изменяют существующий объект.
const date = moment();
date.add(1, 'day');
console.log(date.format());
Метод add() изменяет исходный объект date.
Такое поведение отличается от многих современных библиотек, использующих
неизменяемые структуры данных.
Из-за изменяемости объектов возникает распространённая ошибка: несколько переменных начинают ссылаться на один и тот же объект moment.
const original = moment();
const copy = original;
copy.add(7, 'days');
console.log(original.format());
console.log(copy.format());
Обе переменные содержат одинаковое значение, поскольку
copy не создаёт новый объект, а лишь копирует ссылку.
Для создания независимого экземпляра используется клонирование.
clone()Основной способ клонирования — метод clone().
const original = moment();
const cloned = original.clone();
cloned.add(1, 'month');
console.log(original.format());
console.log(cloned.format());
После вызова clone() создаётся новый объект moment,
содержащий:
При изменении клона оригинальный объект остаётся неизменным.
Внутри библиотеки создаётся новый экземпляр moment с копированием состояния исходного объекта.
const first = moment('2025-01-10');
const second = first.clone();
console.log(first === second);
Результат:
false
Объекты разные, несмотря на одинаковое содержимое.
moment(existingMoment)Существует альтернативный способ создания копии:
const original = moment();
const cloned = moment(original);
Передача объекта moment в конструктор moment()
автоматически создаёт копию.
Это поведение эквивалентно:
const cloned = original.clone();
clone()const copy = original.clone();
Преимущества:
moment(existingMoment)const copy = moment(original);
Преимущества:
const start = moment('2025-05-01');
const nextWeek = start.add(7, 'days');
console.log(start.format('YYYY-MM-DD'));
Результат:
2025-05-08
Исходная дата была изменена.
Правильный вариант:
const start = moment('2025-05-01');
const nextWeek = start.clone().add(7, 'days');
console.log(start.format('YYYY-MM-DD'));
console.log(nextWeek.format('YYYY-MM-DD'));
Результат:
2025-05-01
2025-05-08
Практически любой метод модификации изменяет объект:
add()subtract()startOf()endOf()set()year()month()date()hour()minute()Поэтому распространённый шаблон выглядит так:
const result = date.clone().add(1, 'day');
startOf() / endOf()Методы начала и конца периода особенно часто вызывают побочные эффекты.
const now = moment();
const startDay = now.startOf('day');
console.log(now.format());
now уже изменён.
const now = moment();
const startDay = now.clone().startOf('day');
console.log(now.format());
console.log(startDay.format());
Moment.js поддерживает chaining — цепочки вызовов.
const result = moment()
.clone()
.add(1, 'week')
.startOf('week')
.hour(9);
Клон создаётся один раз, после чего безопасно выполняются модификации.
При использовании плагина Moment Timezone временная зона также копируется.
const moscow = moment.tz(
'2025-03-10 12:00',
'Europe/Moscow'
);
const cloned = moscow.clone();
console.log(cloned.tz());
Результат:
Europe/Moscow
Локаль тоже переносится в новый объект.
const date = moment()
.locale('ru');
const cloned = date.clone();
console.log(cloned.locale());
Результат:
ru
UTC-состояние сохраняется.
const utcDate = moment.utc();
const cloned = utcDate.clone();
console.log(cloned.isUTC());
Результат:
true
После клонирования значения одинаковы, но ссылки различаются.
const a = moment();
const b = a.clone();
console.log(a.isSame(b));
console.log(a === b);
Результат:
true
false
isSame() сравнивает дату и время;=== сравнивает ссылки на объект.Обычные способы копирования объектов JavaScript не подходят.
const copy = { ...moment() };
Moment.js содержит внутренние структуры и методы, которые не копируются корректно.
Аналогично не работают:
Object.assign({}, moment());
или
JSON.parse(JSON.stringify(moment()));
Эти методы создают обычные объекты, а не полноценные экземпляры moment.
При работе с массивами требуется клонировать каждый элемент отдельно.
const dates = [
moment(),
moment().add(1, 'day')
];
const copied = [...dates];
copied[0].add(1, 'month');
Изменится и оригинальный массив.
const copied = dates.map(date => date.clone());
function addWeek(date) {
date.add(1, 'week');
return date;
}
Функция изменяет переданный объект.
function addWeek(date) {
return date.clone().add(1, 'week');
}
Такой подход уменьшает количество скрытых побочных эффектов.
Иногда требуется временно изменить дату для форматирования.
const date = moment();
const formatted = date
.clone()
.utc()
.format();
Исходный объект остаётся в локальном времени.
const current = moment();
const startMonth = current
.clone()
.startOf('month');
const endMonth = current
.clone()
.endOf('month');
Без clone() объект current был бы изменён
несколько раз подряд.
const start = moment('2025-01-01');
const dates = [];
for (let i = 0; i < 5; i++) {
dates.push(
start.clone().add(i, 'days')
);
}
Каждый элемент массива является независимым объектом.
const day = moment();
const monday = day.startOf('week');
const friday = day.endOf('week');
После вызова endOf() объект monday тоже
изменится, поскольку обе переменные указывают на один экземпляр.
Правильный вариант:
const day = moment();
const monday = day
.clone()
.startOf('week');
const friday = day
.clone()
.endOf('week');
Операция clone() достаточно лёгкая, однако при огромном
количестве объектов могут появляться накладные расходы.
Например:
for (let i = 0; i < 100000; i++) {
moment().clone();
}
В большинстве приложений производительность клонирования не становится проблемой, но в высоконагруженных системах количество копий желательно контролировать.
Клонирование требуется практически всегда, если:
Клонирование необязательно, если объект больше нигде не используется.
const result = moment()
.add(1, 'day')
.format();
Исходный объект нигде не сохраняется, поэтому изменение безопасно.
Распространённый подход:
const baseDate = moment();
const tomorrow = baseDate
.clone()
.add(1, 'day');
const nextMonth = baseDate
.clone()
.add(1, 'month');
const endYear = baseDate
.clone()
.endOf('year');
Исходная дата остаётся неизменной независимо от количества вычислений.
| Особенность | Описание |
|---|---|
| Создаёт новый объект | Да |
| Копирует дату и время | Да |
| Копирует локаль | Да |
| Копирует timezone | Да |
| Копирует UTC-состояние | Да |
| Изменения влияют на оригинал | Нет |
| Основной метод | clone() |
const b = a;
Это копирование ссылки.
a.clone().add(1, 'day');
{ ...moment() }
Создаёт некорректную копию.
return date.clone().add(1, 'week');
Функция не должна менять входные данные без необходимости.