newを省略できる、可変引数を取るコンストラクタの作り方
追記:コメントを元に、__proto__を使ったthisのエミュレートをやってみた。結構シンプルでいい。
参考:JavaScript のコンストラクタ関数 - 冬通りに消え行く制服ガールは✖夢物語にリアルを求めない。 - subtech
function defer(){ if(!(this instanceof defer)) return defer.apply({__proto__:defer.prototype},arguments); this.task=Array.slice(arguments); this.next(); return this; } defer.prototype.next=function(){ var self=this; this.arg=this.task.shift().call(this, function() self.next.call(self), this.arg); }
追記ここまで。
JSDeferredのように、newを付けても付けていなくてもうまく動くコンストラクタは、
function constructorFn(a,b,c){ if(!(this instanceof arguments.callee)) return new arguments.callee(a,b,c); }
のように、割と簡単に書くことができるが、コンストラクタの取る引数が可変の場合、
return new arguments.callee.apply(ここに入れるものがない,arguments); // newされる前にarguments.callee.applyが呼ばれてしまう
のように問題が多く、実現するのが難しい。
こういった場合はクロージャを使って、下のように書くことで解決できる。
ただし、コードが分かりづらくなるので、普通に毎回newを付けるようにしたほうがいいかもしれない。
下のコードはを参考にした。
var defer; (function(){ var arg,flag; defer=function(){ if(this instanceof defer){ var a; if(flag)a=arg; else a=arguments; flag=false; this.task=Array.slice(a); this.next(); }else{ flag=true; arg=arguments; return new defer(); } } defer.prototype.next=function(){ var self=this; this.arg=this.task.shift().call(this, function() self.next.call(self), this.arg); } })(); defer(function(next){ console.log("start!"); setTimeout(next,1000); }, function(){ console.log("finish!"); }); // new defer(function(next){…でも動く