記事
- 2011年12月25日 22:30
javascript - からnewを取り除いてみる
1/2
giveするイベントも終わったところで、takeしたいと思います。
JavaScriptから、newを。
"JavaScript: the Good Parts"も言葉では指摘していますが、実演まではしていないので以下で改めて。
要するに、
Pythonistas にしたら new なんてつける方がおかしいですし、Perl Mongers や Rubyists も
この
でもこんなひちめんどくさいこといちいちやらなければならないのでしょうか?
それにあたっては、
new - MDN
これだと、うまく行きません。
JavaScriptから、newを。
だぐらす「すべてのnewを、生まれる前に消し去りたい」
newはなぜ危険か
"JavaScript: the Good Parts"も言葉では指摘していますが、実演まではしていないので以下で改めて。
(function(){ var o, /* なんの変哲もないコンストラクター */ Point = function Point(x, y){ this.x = x; this.y = y; }; try{ o = new Point(3, 4); p(JSON.stringify(o)); /* {"x":3,"y":4} */ p(x); p(y); /* exception thrown */ }catch(e){ p(e); /* ReferenceError: Can't find variable: x */ } try{ o = Point(3, 4); /* new を忘れると… */ p(JSON.stringify(o)); /* undefined // なんで? */ p(x); p(y); /* 3; 4; // なんでなんで? */ }catch(e){ p(e); /* ここにはこない */ } try{ /* clean it up */ delete this.x; delete this.y; p(x); p(y); }catch(e){ p(e); /* ReferenceError: Can't find variable: x */ } })();
要するに、
newをつけ忘れてコンストラクターを呼び出すと、thisがグローバルネームスペースを指しているので知らないうちにグローバル変数を定義したり上書きしたりしちゃうということなのですね。Pythonistas にしたら new なんてつける方がおかしいですし、Perl Mongers や Rubyists も
Constructor.new() と書けない点がひっかかります。安全なコンストラクターの書き方
この
thisが何を指し示すかを調べれば、newをつけようがつけまいがnewしてくれるコンストラクターを作れます。(function(){ var o, Point = function Point(x, y){ if (this instanceof Point){ /* new されたらこっち */ this.x = x; this.y = y; }else{ return new Point(x, y); /* されなかったら改めてnew */ } }; try{ o = new Point(3, 4); p(JSON.stringify(o)); /* {"x":3,"y":4} */ p(x); p(y); /* exception thrown */ }catch(e){ p(e); /* ReferenceError: Can't find variable: x */ } try{ o = Point(3, 4); /* 今度はつけ忘れても… */ p(JSON.stringify(o)); /* {"x":3,"y":4} */ p(x); p(y); /* exception thrown */ }catch(e){ p(e); /* ReferenceError: Can't find variable: x */ } })();
でもこんなひちめんどくさいこといちいちやらなければならないのでしょうか?
newを自作してみる
それにあたっては、
newが何をしているかを改めて確認しておきましょう。new - MDN
このとおりのことをする関数は自作できるでしょうか?
When the codenew foo(...)is executed, the following things happen:
- A new object is created, inheriting from
foo.prototype.- The constructor function
foois called with the specified arguments andthisbound to the newly created object.new foois equivalent tonew foo(), i.e. if no argument list is specified,foois called without arguments.- The object returned by the constructor function becomes the result of the whole
newexpression. If the constructor function doesn't explicitly return an object, the object created in step 1 is used instead. (Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.)
これだと、うまく行きません。
var newer = function(cf, args){ var seed = {}; /* A new object is created */ seed.constructor = cf; /* inheriting from foo.prototype */ return cf.apply(seed, args) /* The constructor function foo is called... */ || seed; /* If the constructor function doesn't * explicitly return an object, * the object created in step 1 is used * instead. */ }; var o, Point = function Point(x, y){ this.x = x; this.y = y; }; Point.prototype.fromOrigin = function(){ return Math.sqrt(this.x*this.x + this.y*this.y) }; try{ o = newer(Point, [3, 4]); p( JSON.stringify(o) ); /* 一見うまく行っているんだけど… */ p( o instanceof Point ); /* うーん、だめだ */ p( o.fromOrigin() ); /* 爆発しろ */ }catch(e){ p(e); }



