Comment contourner la mutabilité dans moment.js?

107

J'ai rencontré un problème où je dois stocker les valeurs initiales d'un objet moment mais j'ai du mal à empêcher ma variable de changer avec l'objet d'origine.

Malheureusement, Object.freeze () ne fonctionne pas, car moment.js renvoie une erreur "Date invalide" lorsque j'essaye de formater cela.

Shengbo1618
la source
3
Et le code ressemble à…? Si vous souhaitez stocker la valeur initiale, stockez la valeur de temps, disponible à l'aide de la méthode valueOf ou d'une conversion implicite en nombre.
RobG
une fois que votre variable est définie, elle est définie, elle ne changera pas automatiquement, alors cherchez plutôt à ne pas la définir encore et encore
john Smith

Réponses:

185

Il existe un plugin Moment.js sur NPM appelé Frozen -moment - Vous pouvez utiliser moment().freeze()à la place de Object.freeze(moment()).

Sinon, vanilla Moment.js a une cloneméthode qui devrait vous aider à éviter les problèmes de mutabilité, vous pouvez donc faire quelque chose comme ceci:

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

METTRE À JOUR:

Cela fait deux ans que j'ai écrit cette réponse. À cette époque, une autre bibliothèque pour travailler avec les dates a fait surface et a gagné beaucoup de popularité: https://date-fns.org/

Cette bibliothèque est immuable par défaut et suit une architecture modulaire et fonctionnelle, ce qui signifie qu'elle est mieux adaptée à l'arborescence et au regroupement côté client. Si vous travaillez sur un projet qui utilise largement Webpack côté client et que Moment.js vous pose des problèmes avec votre build, ou même si la mutabilité de Moment.js vous cause beaucoup de maux de tête, alors vous devrait date-fnsessayer.

razorbeard
la source
Eh bien, j'utilise moment.js dans le plugin fullCalendar et il s'avère que je recevais les données d'objet moment à partir d'un état plus tardif de mon événement que je ne devais le faire. Les problèmes de mutabilité sont certainement une chose avec moment.js, alors merci beaucoup pour la suggestion et désolé d'avoir perdu votre temps.
Shengbo1618
24
Vous pouvez manipuler la momentvariable stockée sans la muter: utilisez simplement clone () comme ceci:zz = moment(); zz.clone().add(3, 'h').toISOString();
Quake1TF
5
Notez que date-fns a une très mauvaise prise en charge des fuseaux horaires et aucune prise en charge des dates UTC.
mjuopperi
3
J'utilise date-fnsdepuis un moment maintenant, mais j'ai depuis dû sauter dans le code hérité en utilisant Moment and boy, est-ce que cet article m'a évité de sauter par une fenêtre.
Yuschick
dayjsest également une bonne alternative car il possède des API similaires à Moment.js avec une nature immuable. (En mars 2019, il ne prend pas en charge le fuseau horaire, mais il s'agit d'une bibliothèque assez récente et je peux observer que le travail est en cours.)
Tomoyuki Aota
2

C'est une vieille question et des excuses pour l'auto-promotion éhontée car ce n'est pas mon intention, j'espère juste que cela aidera quelqu'un.

En plus de ce que dit razorbeard ( .clone()etc.), j'ai créé un module NPM qui attache des méthodes immuables à tout ce que Moment.js est livré avec. L'intention n'est pas de casser le code existant afin que le module ajoute de nouvelles méthodes avec Immuen plus son nom.

Chaque instance retournée par moment factory sera décorée avec des méthodes immuables, par exemple moment().startOf()aura correspondant startOfImmu(), add()aura addImmu()etc. Chacune de ces instances renvoie un nouveau moment plutôt que de modifier l'existant. Pour l'utiliser, il suffit de passer momentfactory à momentImmutableMethodspour accéder à de nouvelles méthodes immuables. Exemple:

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"

C'est sur NPM à https://www.npmjs.com/package/moment-immutable-methods

spiryte
la source