JavaScriptでクラス定義する時、クロージャを使う場合とprototypeを使う場合の違い

クロージャを使ってクラス定義する例が以下。

function FooClass(a) {
    this.getA = function() {
        return a;
    }
    this.square = function() {
        return a * a; 
    }
}

prototypeを使ってクラス定義する例が以下。

function BarClass(a) {
    this.a = a
}
BarClass.prototype = {
    "getA" : function() {
        return this.a;
    },
    "square" : function() {
        return this.a * this.a;
    }
}

クロージャを使っている場合は、オブジェクトが生成されるたびに違った関数オブジェクトがメソッドとして登録されるが、prototypeを使っている場合は、オブジェクトが生成された時にメソッドとして登録されるのは毎回同じ関数オブジェクトである。これは、以下のようなコードで確認できる。

alert(new FooClass().getA === new FooClass().getA); // false
alert(new BarClass().getA === new BarClass().getA && new BarClass().getA === BarClass.prototype.getA); // true

このことは10万個オブジェクトを生成する以下のベンチマークにも表れる。

<html><head></head><body>
<script type="text/javascript">

function time(callback) {
    var before = new Date().getTime();
    callback();
    return new Date().getTime() - before;
}

function FooClass(a) {
    this.getA = function() {
        return a;
    }
    this.square = function() {
        return a * a; 
    }
}

function BarClass(a) {
    this.a = a
}
BarClass.prototype = {
    "getA" : function() {
        return this.a;
    },
    "square" : function() {
        return this.a * this.a;
    }
}

document.write("FooClass(using closure): " + time(function() {
    for (var i = 0; i < 100000; i++) new FooClass(i); 
}) + "ms<br>");

document.write("BarClass(using prototype): " + time(function() {
    for (var i = 0; i < 100000; i++) new BarClass(i);
}) + "ms<br>");

</script>
</body></html>

実行するブラウザにもよるがだいたい2-6倍程度でprototypeを使った場合の方が速い。これは、クロージャを使う場合はオブジェクトを生成するたびに新しい関数オブジェクトも生成するためだと考えられる。