JavaScript に new 演算子は要らない

 

JavaScript ほどの記述性の高さがあれば、実は new 演算子は要らないのではないか? という疑惑を抱いて悶々としていたのが解決しました。

気になっていた JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス を入手してパラパラめくったら、信じられないことに「悪いパーツ」に new 演算子が載っているではありませんか!

本書では new 演算子を使うべきでない理由を述べるとともに、関数型パターンによるアプローチを紹介しています。 ここでは気に入ったフレーズだけ引用しておきます(p.57)。

擬似クラス型のスタイルは、JavaScriptになじみのないプログラマに安心感を与えることができる。 しかし同時にこのスタイルは、JavaScriptの本質を隠してもしまう。
何故、このフレーズが気に入ったのか? それは「本質」という言葉が好きだからです :-)

疑惑の発端

1. new 演算子と apply メソッドは何が違うのだろう?

js> var foo = function(x,y){
      this.add = function(){ return x + y; };
      return this;
    }
js> var bar1 = new foo(2,3);
js> var bar2 = new foo(4,5);
js> var qux1 = foo.apply({},[2,3]);
js> var qux2 = foo.apply({},[4,5]);
js> bar1.add();
5
js> bar2.add();
9
js> qux1.add();
5
js> qux2.add();
9

2. クロージャの存在 ☞ JavaScript とクロージャ

実験

冒頭の本に書かれている関数型パターンとは別に、 自分なりに new 演算子を使わないコードを書いてみました(実用性を求めない実験です)。 コードの概要は次の通りです。

  • 擬似クラス型の雰囲気はそのままで、new 演算子の代わりに apply メソッドを使用する。
  • 擬似クラス型のままで new 演算子を使わないということは、プロトタイプチェーン(__proto__)を自力で操作するということ。 これがどれ程のことなのか試してみる。
  • プロトタイプチェーンを自力で操作するのであれば、prototypeプロパティは要らないのではないか。 試しに、独自に extプロパティを導入してみる。

ソースコード

nonew.js
#!/usr/local/bin/js

var foo = function(){         // 入出力器
    var x, y;
    this.set = function(a,b){ x = a; y = b; };
    this.x = function(){ return x; };
    this.y = function(){ return y; };
    return this;
};
foo.ext = {
    out: function(){
        print('x=' + this.x() + ',y=' + this.y());
    }
};

var bar = function(){         // 加減器
    this.add = function(){ return this.x() + this.y(); };
    return this;
};
bar.ext = {
    sub: function(){ return this.x() - this.y(); }
};

var qux = function(){         // 乗除器
    this.mul = function(){ return this.x() * this.y(); };
    return this;
};
qux.ext = {
    div: function(){ return this.x() / this.y(); }
};

var obj = (function(){        // 組み立て
    var that = {};
    foo.apply(that)   .__proto__ = foo.ext;  // foo.ext をチェーンの先頭へ
    bar.apply(foo.ext).__proto__ = bar.ext;  // bar.ext をチェーンの中央へ
    qux.apply(bar.ext).__proto__ = qux.ext;  // qux.ext をチェーンの後尾へ
    return that;
})();

obj.set(20,5);                // 試運転
obj.out();
print("x+y=" + obj.add());
print("x-y=" + obj.sub());
print("x*y=" + obj.mul());
print("x/y=" + obj.div());

実行結果

$ chmod +x nonew.js
$ ./nonew.js
x=20,y=5
x+y=25
x-y=15
x*y=100
x/y=4

覚え書き

実験を終えて

  • ほとんどブラックボックスが無いので見通しが良い。
  • __proto__ がゴツい。 ついでに、IE では使えない。
  • どんな穴(問題)があるのか想像できない。
  • 価値のあるパターンを生み出すのは大変なことだ。

更新履歴

日付 内容
2009-12-29 追加 セクション「関連リンク」
2009-02-26 追加 セクション「疑惑の発端」
2009-02-24 追加 セクション「実験」「覚え書き」
2009-02-13 初版