3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[実験] JavaScriptのデフォルトのDateオブジェクトをハックする [考察]

Last updated at Posted at 2018-03-20

TL;TD;

JavaScriptのデフォルトのDateオブジェクトは月が0$\sim$11で使いにくいのでES2015から導入されたclassの継承を使ってハックする。

JavaScriptによるclassの継承

classの継承を使うことで、prototypeを拡張することなくデフォルトのDateオブジェクトをハックする。

modDate.js
module.exports=class extends Date{
    constructor(...args){
        if( args.length<2 ) super(...args);
        else{
            const year=args.shift();
            const month=args.shift()-1;
            super( year, month, ...args);
        }
    }

    getYear(){ return super.getFullYear(); }

    setMonth(month){ super.setMonth(month-1); }
    getMonth(month){ return super.getMonth()+1; }
}

Nodeでmodule.exportsで名前をつけずexportした。ブラウザ用ならexports defaultである。
月をセットするセッターとコンストラクタは1を引いてデフォルトを呼ぶ。
特にコンストラクターはrest parametersを用いて文字列、エポック秒を用いたコンストラクタはデフォルトのコンストラクタにそのまま渡し。月が関わるものだけ、配列のshiftを使って月まで取り出して残りはデフォルトのコンストラクタに渡している。
ゲッターは1を足して返すようにしている。
getYearは非推奨であり2018=>118というややこしい値を返すので内部でgetFullYearを返すようにした(同じくsetYearもハックするべきかもしれない)。

検証用コード

ここでは同じ名前のDateがブロックスコープを変えることで共存できることも検証したが安全性としては問題が残るので実際に使う場合はより安全な名付けとルール作りが必要である。

testModDate.js
{
    console.log('===== modified Date Object Test START =====');
    const Date=require('modDate');

    const date=new Date();
    console.log(date);
    console.log(date.getYear());

    const monthArr=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ];
    for( const month of monthArr ){
        console.log("Month =", month);
        date.setMonth(month);
        console.log(date);
        console.log("date.getMonth()=", date.getMonth());
        const date2=new Date(1000, month, 10);
        console.log(date2);
    }

    console.log('===== modified Date Object Test FINISH =====');
}

console.log('===== default Date Object Test START =====');
const date=new Date();
console.log(date);
console.log(date.getYear());

const monthArr=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ];
for( const month of monthArr ){
    console.log("Month =", month);
    date.setMonth(month);
    console.log(date);
    console.log("date.getMonth()=", date.getMonth());
}

console.log('===== default Date Object Test FINISH =====');

modDateファイルをDateで受けることによりあたかもDateのように使うことができる。また、constなので影響範囲はブロックスコープに限られるので外ではデフォルトのDateとして使える。

まとめ

classのextends(継承)を使うことで影響範囲を限った形で既存のインスタンスをハックできる。
rest parametersを用いることで様々な値を受けられるコンストラクター(関数)にも簡単に対応できる。
影響範囲が限られているのでガンガン書き換えても問題は大きくならないので例えばgetDayあたりを日、月、火、....とかにするのもアリだろうし。toStringをより読みやすい形に変えるなどもできそうである。

コメントを受けて

getDaygetDayJaもしくはgetDayStringJaにするべきだと思う。あえてgetYoubiとかでもいいかも
toStringはあえて名前つけルールを標準からずらしてstringもしくはforLogとかがありだと思います。

3
0
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?