Como faço para contornar a mutabilidade no moment.js?

106

Tive um problema em que preciso armazenar os valores iniciais de um objeto de momento, mas estou tendo alguns problemas para evitar que minha variável mude junto com o objeto original.

Infelizmente Object.freeze () não funciona, porque moment.js retorna um erro de "Data inválida" quando tento formatar isso.

Shengbo1618
fonte
3
E o código parece ...? Se você deseja armazenar o valor inicial, armazene o valor de tempo, disponível usando o método valueOf ou conversão implícita em número.
RobG de
uma vez que sua variável é definida, ela está definida, ela não mudará automaticamente, então procure não defini-la novamente e novamente
john Smith

Respostas:

184

Há um plugin Moment.js no NPM chamado frozen-moment - você pode usar moment().freeze()no lugar de Object.freeze(moment()).

Caso contrário, vanilla Moment.js tem um clonemétodo que deve ajudá-lo a evitar problemas de mutabilidade, então você pode fazer algo assim:

var a = moment(),
    b = a.clone(); // or moment(a)

ATUALIZAR:

Já se passaram dois anos desde que escrevi esta resposta. Nesse tempo, outra biblioteca para trabalhar com datas surgiu e ganhou muita força: https://date-fns.org/

Essa biblioteca é imutável por padrão e segue uma arquitetura modular e funcional, o que significa que é mais adequada para agitação de árvore e empacotamento do lado do cliente. Se você está trabalhando em um projeto que faz uso extensivo de Webpack no lado do cliente e descobre que Moment.js está causando problemas com sua construção, ou mesmo se a mutabilidade do Moment.js está causando muita dor de cabeça, então você deve dar date-fnsuma chance.

razorbeard
fonte
Bem, estou usando moment.js no plug-in fullCalendar e descobri que estava obtendo os dados do objeto de momento de um estado posterior do meu evento do que deveria. No entanto, problemas de mutabilidade são definitivamente uma coisa com moment.js, então muito obrigado pela sugestão e desculpe por ter perdido seu tempo.
Shengbo1618
24
Você pode manipular a momentvariável armazenada sem alterá-la: basta usar clone () assim:zz = moment(); zz.clone().add(3, 'h').toISOString();
Quake1TF
5
Observe que date-fns tem suporte de fuso horário muito pobre e nenhum suporte para datas UTC.
mjuopperi de
3
Eu tenho usado date-fnspor um tempo, mas desde então tive que pular para o código legado usando o Moment e cara, esse post me salvou de pular de uma janela.
Yuschick
dayjstambém é uma boa alternativa, pois tem APIs semelhantes a Moment.js com natureza imutável. (Em março de 2019, ela não tinha suporte de fuso horário, mas esta é uma biblioteca relativamente nova e posso observar que o trabalho está em andamento.)
Tomoyuki Aota
2

É uma velha pergunta e desculpas pela autopromoção sem vergonha pois essa não é a minha intenção, só espero que ajude alguém.

Além do que diz razorbeard ( .clone()etc), criei um módulo NPM que anexa métodos imutáveis ​​a tudo o que o Moment.js vem pronto para uso. A intenção não é quebrar o código existente, então o módulo adiciona novos métodos com Immuanexado ao seu nome.

Cada instância retornada pela fábrica de momento será decorada com métodos imutáveis, por exemplo moment().startOf(), terá correspondente startOfImmu(), add()terá addImmu()etc. Cada um desses retorna um novo momento ao invés de modificar um existente. Para usá-lo, basta passar de momentfábrica momentImmutableMethodspara obter acesso a novos métodos imutáveis. Exemplo:

var moment = require('moment'); // or moment-timezone 
import { momentImmutableMethods } from 'moment-immutable-methods';

// to decorate instances with immutable methods we need to extend moment factory as below:
momentImmutableMethods(moment);

// now every instance returned by moment will have Immu methods attached.


// IMMUTABLE EXAMPLE
// we using immutable methods that were attached to every instance, these have Immu appended to original name
const ddd = moment({
  hour: 5,
  minute: 10
});
// Moment {_isAMomentObject: true, _i: {…}, _isUTC: false, _pf: {…}, _locale: Locale, …}
const eee = ddd.startOfImmu('day');
// Moment {_isAMomentObject: true, _i: {…}, _isUTC: false, _pf: {…}, _locale: Locale, …}
console.log(ddd === eee);
// false
const fff = eee.startOfImmu('month');
// Moment {_isAMomentObject: true, _i: {…}, _isUTC: false, _pf: {…}, _locale: Locale, …}
console.log(ddd === fff);
// false
console.log(eee === fff);
// false
console.log(ddd.format('DD/MM/YY HH:mma'));
// "14/04/18 05:10am"
console.log(eee.format('DD/MM/YY HH:mma'));
// "14/04/18 00:00am"
console.log(fff.format('DD/MM/YY HH:mma'));
// "08/04/18 00:00am"

Está no NPM em https://www.npmjs.com/package/moment-immutable-methods

spirytus
fonte