読者です 読者をやめる 読者になる 読者になる

javascriptのモジュールパターンとprototype継承について

jsを書くとき、今まであまりprototype継承を使用せず、どちらかというとモジュールパターンで記述することが多かったので、それぞれ何が違うのか、あまり理解していませんでした。
それを今日教えてもらえたので、まとめます。

モジュールパターンとは

function Hoge() {
    var n = 1;

    return {
        fuga: function() {
            alert(n);
        }
    };
}

var hoge = new Hoge;
hoge.fuga(); // 「1」がalertで表示される
hoge.n; // Error

このように、関数の返り値をobjectで返し、さらにそのobjectの中にfunctionを用意します。
fugaの中で参照しているnはクロージャの中で生き続けるので、外からでもアクセスできますが、直接は参照できません。

この、クロージャを利用してprivateやpublicな変数やメソッドを作る仕組みがモジュールパターンです。

参考 http://aphall.com/2013/06/javascript-iife-module-pattern/

prototype継承とは

function Hoge(txt) {
    this.txt = txt;
} 
Hoge.prototype.fuga = function() {
    alert(this.txt);
};
function Foo() {
}
Foo.prototype = new Hoge('Hello');
var foo = new Foo;
foo.fuga(); // 「Hello」がalertで表示される

Fooには本来fugaメソッドはありませんが、FooのprototypeにHogeのインスタンスを代入することで、fugaメソッドをprototypeをたどって探しにいき、最終的にはHogeのprototypeに定義されているfugaメソッドが実行されます。

参考 https://gist.github.com/yoshimuraYuu/3301790

ハマったところ

『モジュールパターンで作成したものを、継承できるようにしたい』

function Hoge(txt) {
    this.txt = txt;
} 
Hoge.prototype.fuga = function() {
    alert(this.txt);
};
function Piyo() {
    return {
        bar: function() {
        }
    };
}
Piyo.prototype = new Hoge('Hello');
var piyo = new Piyo;
piyo.fuga(); // Error

この例は、Errorになります。
Piyoはモジュールパターンなので、Piyoの実行の返り値はobjectです。
objectにはprototypeは当然無いので、prototype継承ができるはずもなく、Errorになってしまいます。

サンプルをjsdo.itに作ってみました。


結論

モジュールパターンで実装されているものを、Prototype継承するためには書き直すしかない

まとめ

  • モジュールパターンはprivateな変数やメソッドを簡単に定義できるが、継承はできない
  • Prototype継承は変数をメソッド内で使用したい時はglobalにするしかない
    • 基本的にthisに入れてしまうので、外からでもアクセスできてしまう(厳密にprivateにはできない)

なので、個人的にはモジュールパターンの方が好きなんですが、モジュールパターンで作ったものを継承できるように書き直すのは非常にめんどくさいです。
モジュールパターンは使いどころを見極めるべきなんですかね。js難しいです...。