JavaScriptのnew
JavaScriptのnewは危険だよんとCrockfordの本にもありますが、あんまり意味がわかってなかったのですこし調べてみました。
そしたら
John Resig - Simple “Class” Instantiation
に全て書いてありました(英語に自信無いけどたぶん)。
単純にやると以下のようになります。
function User(first, last){ this.name = first + " " + last; } var user = new User("John", "Resig"); user.name // "John Resig"
しかしこの方法だとnewを忘れた場合に問題があります。thisにグローバルオブジェクトがセットされるためグローバル変数を上書きしてしまいます。
var user = User("John", "Resig"); user // undefind name // "John Resig"
これを防ぐために以下のようにすることもできますが、もっと汎用的なものがjqueryには用意されています。
function User(first, last){ if ( this instanceof User ) { this.name = first + " " + last; } else return new User(first, last); }
それがmakeClass関数です。なんか黒魔術的ですね。makeClassは無名関数を返します。
function makeClass(){ return function(args){ if ( this instanceof arguments.callee ) { if ( typeof this.init == "function" ) this.init.apply( this, args.callee ? args : arguments ); } else return new arguments.callee( arguments ); }; }
使い方はこんな感じ。
var User = makeClass(); User.prototype.init = function(first, last){ this.name = first + " " + last; }; var user = User("John", "Resig"); user.name // => "John Resig"
User("John", "Resig")が呼ばれると(newが無いので)makeClassのelseに入ります(argumentsは["John", "Resig"])。そしてthis.init.applyに入ります。つまりmakeClassは2回呼ばれる。
this.init.apply( this, args.callee ? args : arguments )はthis.init.apply( this, args)となります(argsは["John", "Resig"])。
new User("John", "Resig")とすると結果は同じだけどいきなりmakeClassのthis.init.applyに入る。つまりmakeClassが呼ばれるのは1回だけ。
this.init.apply( this, args.callee ? args : arguments )はthis.init.apply( this, arguments)となる(argsは"John",argumentsは["John", "Resig"])。
ややこしいですね。