Объекты Moment в библиотеке Moment.js изменяемы. Это означает, что любые операции над датой и временем чаще всего модифицируют исходный экземпляр, а не создают новый.
Такое поведение критически важно учитывать при построении логики, где один и тот же объект даты используется в разных частях программы.
const a = moment();
const b = a.add(1, 'day');
console.log(a.format());
console.log(b.format());
В данном примере оба значения будут одинаковыми, поскольку
add изменяет исходный объект a. Переменная
b лишь ссылается на тот же самый изменённый экземпляр.
Подобная особенность часто становится источником скрытых ошибок, особенно в сложных вычислениях или при повторном использовании даты.
В реальных приложениях один и тот же объект Moment может участвовать в нескольких вычислениях: расчёте диапазонов, формировании отчётов, сравнении дат.
Если не учитывать мутацию, логика начинает «перетекать» между частями кода:
const base = moment('2024-01-01');
const start = base.add(7, 'days');
const end = base.add(7, 'days');
Ожидаемое поведение — получить две разные даты относительно исходной. Фактически же оба вызова работают с уже изменённым объектом, и результат становится некорректным.
Для предотвращения подобных эффектов используется клонирование
объектов Moment. Метод clone() создаёт новый экземпляр с
тем же состоянием, но полностью независимый от оригинала.
const base = moment('2024-01-01');
const start = base.clone().add(7, 'days');
const end = base.clone().add(14, 'days');
Теперь каждое вычисление опирается на отдельную копию, и изменения не влияют друг на друга.
Клонирование в Moment.js — это не глубокое копирование структуры JavaScript-объекта в классическом смысле, а создание нового обёрнутого объекта с теми же внутренними временными данными.
Использование clone() становится необходимым в
ситуациях, где объект даты:
Пример с функцией:
function addBusinessDays(date, days) {
return date.clone().add(days, 'days');
}
const base = moment('2024-01-01');
const result1 = addBusinessDays(base, 5);
const result2 = addBusinessDays(base, 10);
Без клонирования функция начала бы изменять входной аргумент, что привело бы к накоплению изменений и потере исходного значения.
Несмотря на важность clone(), его использование не
всегда оправдано. В некоторых случаях намеренная мутация упрощает код и
снижает количество операций.
Клонирование можно не использовать, если:
const date = moment();
date.add(2, 'hours');
date.subtract(30, 'minutes');
Здесь мутация является частью последовательного вычисления и не приводит к побочным эффектам.
Moment.js активно использует цепочки вызовов, и важно понимать, как клонирование влияет на них.
const result = moment('2024-01-01')
.clone()
.add(1, 'month')
.subtract(3, 'days');
Клонирование в начале цепочки фиксирует исходное значение, после чего все последующие операции работают с независимой копией.
Если же clone() не используется, исходный объект
изменяется, что может повлиять на другие части программы, использующие
ту же дату.
Одной из наиболее частых причин неожиданных изменений является передача Moment-объекта в функцию без клонирования.
function setEndOfDay(date) {
return date.endOf('day');
}
const base = moment('2024-01-01');
const result = setEndOfDay(base);
console.log(base.format());
В этом случае base будет изменён, поскольку
endOf модифицирует исходный объект.
Безопасный вариант:
function setEndOfDay(date) {
return date.clone().endOf('day');
}
Такой подход гарантирует, что входной параметр остаётся неизменным, а функция возвращает новый результат.
Особую осторожность необходимо проявлять при работе в циклах, где один и тот же объект используется многократно.
const base = moment('2024-01-01');
const dates = [];
for (let i = 0; i < 5; i++) {
dates.push(base.clone().add(i, 'days'));
}
Каждая итерация создаёт независимую дату. Без клонирования массив содержал бы несколько ссылок на один и тот же изменённый объект, что делает результат непредсказуемым.
Клонирование в Moment.js связано с созданием нового объекта и копированием внутреннего состояния. Это имеет стоимость, особенно при массовых операциях.
В высоконагруженных сценариях:
избыточное использование clone() может стать заметным
фактором нагрузки.
Поэтому важно балансировать между безопасностью (избежание мутаций) и производительностью (минимизация лишних копий).
В проектах, где требуется предсказуемость состояния, часто применяется единый подход: любые операции над датами выполняются только через клонирование.
const safeDate = moment(inputDate).clone();
const adjusted = safeDate.clone().add(10, 'days');
const formatted = adjusted.clone().format('YYYY-MM-DD');
Такой стиль делает поведение кода детерминированным и снижает риск скрытых изменений состояния, особенно при масштабировании приложения или работе в команде.