昨日の「JavaScriptでシーケンシャルな作業をゆっくりと行う方法」で自作のtaskman.jsを紹介しましたが、最初は、JSDeferred(http://cho45.stfuawsc.com/jsdeferred/doc/intro.html)を使おうかと思ってました。やることを限定すれば関数2つで済んでしまうので、気まぐれでtaskman.jsを書いたのですが、もっと色々やりたいならJSDeferredのようなチャンとしたライブラリがお勧めです。
ところで、JSDeferredのソースに次の1行がありました。
function Deferred () { return (this instanceof Deferred) ? this.init() : new Deferred() }
最初、「ん? なんだこれ」と思ったのですが、しばらく眺めて「オオオーッ、これはいい!」と叫んでしまいました。これは、newが不要なコンストラクタを作る方法です。
2006年に「newが嫌いな理由 -- リテラル好き好き」という記事を書き、そのなかで次のように言っています。
Pythonはほとんど使ったことがないのですけど、「いいなぁ」と思う点はインスタンス生成にnewが不要なこと。クラス名を関数呼び出し形式で使えばいいだけ、
x = Person('Tonkichi')
。いいなぁ。
2006年の記事では、しょうがないのでコンストラクタ呼び出しをラップする関数を書いてました。
function v2(x, y) { return new Vector2D(x, y); }
上記のJSDererredで使われている方法なら次のように書けます。
function Vector2D(x, y) { if (!(this instanceof Vector2D)) return new Vector2D(x, y); this.x = x; this.y = y; return true; }
this instanceof クラス名
として判断しているところがミソです。new付きでコンストラクタ関数が呼ばれると、thisにはそのクラスのインスタンスオブジェクトが入ります。普通のグローバル関数として呼ばれるとグローバルオブジェクトがthisに入ります。よって、Vector2D(3, 2) のように呼び出すと、new Vector2D(3, 2) と同じ効果があります。
5年前の不満が今ごろ解消されました。