JavaScriptのオブジェクトの機能にはクローンが備わっていません。構造を持つデータのクローンをする際も次の様な方法が取られることが多いです。
// ネストした深い部分もクローン出来る const cloneObj = JSON.parse(JSON.stringify(obj)); // ネストした深い部分はクローンできない const cloneObj = {...obj};
どちらもメソッドを複製できないという欠点があります。この欠点を補うために lodash の様な巨大なライブラリを読み込んだり手製の変換処理を作ったりと工夫する必要があります。この記事では Date オブジェクトについていい感じの複製方法を紹介します。実際の複製コードが次です。
// originalDate には任意の Date オブジェクトが格納されている想定です const replicatedDate = new Date(originalDate.getTime());
大変シンプルです。複製元の Date オブジェクトからタイムスタンプを取得し、タイムスタンプを元に新たな Dateオブジェクトを生成しています。これだけならば特別な何かは必要なく素のJavascriptでもできます。
このコードは date-fns のソースコードから抜き出したコードです。引用元である date-fns では次の様になっています。
date-fns/index.ts at main · date-fns/date-fns
export default function toDate<DateType extends Date = Date>( argument: DateType | number ): DateType { const argStr = Object.prototype.toString.call(argument) // Clone the date if ( argument instanceof Date || (typeof argument === 'object' && argStr === '[object Date]') ) { // Prevent the date to lose the milliseconds when passed to new Date() in IE10 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: TODO find a way to make TypeScript happy about this code return new argument.constructor(argument.getTime()) // return new Date(argument.getTime()) } else if (typeof argument === 'number' || argStr === '[object Number]') { // TODO: Can we get rid of as? return new Date(argument) as DateType } else { // TODO: Can we get rid of as? return new Date(NaN) as DateType } }
この関数は数値やDateオブジェクトから新しいDateオブジェクトを返す関数です。これの中にある new argument.constructor(argument.getTime())
がなるほど、となって紹介した部分です。ちなみにここでnew Date
でなくnew argument.constructor
としているのは Date を拡張したオブジェクトが渡ってきた時、Dateそのものではなく拡張版のオブジェクトを返すためです。情報が落ちないライブラリのユーザーに優しいつくりです。
date-fns のソースコードは日時操作に関する小さな関数の集まりです。最も複雑な部分は Date を特定のフォーマットに変換する format 関数に関する部分ですが、それでも処理本体は200行未満です。そういったわけでライブラリを増やさずに日時をどうこうする時、date-fnsのソースコードは大いに参考になります。