Skip to content

Latest commit

 

History

History
103 lines (69 loc) · 5.07 KB

File metadata and controls

103 lines (69 loc) · 5.07 KB

コンストラクタ

JavaScriptのコンストラクタは色々ある他のプログラム言語とは一味違います。newキーワードが付いているどんな関数呼び出しも、コンストラクタとして機能します。

コンストラクタ内部では -呼び出された関数の事です- thisの値は新規に生成されたObjectを参照しています。この新規のオブジェクトのprototypeは、コンストラクタとして起動した関数オブジェクトのprototypeに設定されています。

もし呼び出された関数が、returnステートメントを明示していない場合は、暗黙の了解でthisの値を -新規のオブジェクトとして- 返します。

function Foo() {
    this.bla = 1;
}

Foo.prototype.test = function() {
    console.log(this.bla);
};

var test = new Foo();

上記は、Fooをコンストラクタとして呼び出し、新規に生成されたオブジェクトのprototypeFoo.prototypeに設定しています。

明示的にreturnステートメントがある場合、関数は返り値がObjectである場合に限りステートメントで明示した値を返します。

function Bar() {
    return 2;
}
new Bar(); // 新しいオブジェクト

function Test() {
    this.value = 2;

    return {
        foo: 1
    };
}
new Test(); // 返ってきたオブジェクト

newキーワードが省略されている場合は、関数は新しいオブジェクトを返す事はありません

function Foo() {
    this.bla = 1; // グローバルオブジェクトに設定される
}
Foo(); // undefinedが返る

JavaScriptのthisの働きのせいで、上記の例ではいくつかのケースでは動作するように見える場合がありますが、それはグローバルオブジェクトthisの値として使用されるからです。

ファクトリー

newキーワードを省略するためには、コンストラクタ関数が明示的に値を返す必要があります。

function Bar() {
    var value = 1;
    return {
        method: function() {
            return value;
        }
    }
}
Bar.prototype = {
    foo: function() {}
};

new Bar();
Bar();

Barで呼び出されたものは両方とも全く同じものものになります。これには、methodと呼ばれるプロパティを持ったオブジェクトが新しく生成されますが、これはクロージャです。

また、注意する点として呼び出されたnew Bar()は返ってきたオブジェクトのプロトタイプに影響しません。プロトタイプは新しく生成されたオブジェクトにセットされはしますが、Barは絶対にその新しいオブジェクトを返さないのです。

上記の例では、newキーワードの使用の有無は機能的に違いがありません。

ファクトリーとして新しくオブジェクトを作成する

多くの場合に推奨される事として、newの付け忘れによるバグを引き起こしやすいので、newを使用しないようにするという事があります。

新しいオブジェクトを作成するためにファクトリーを使用して、そのファクトリー内部に新しいオブジェクトを作成すべきだという事です。

function Foo() {
    var obj = {};
    obj.value = 'blub';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}

上記の例ではnewキーワードが無いため堅牢になりますし、確実にプライベート変数を使用するのが簡単になりますが、いくつかの欠点があります。

  1. 作られたオブジェクトがプロトタイプ上のメソッドを共有しないために、よりメモリーを消費してしまいます。
  2. ファクトリーを継承するために、他のオブジェクトの全てのメソッドをコピーする必要があるか、新しいオブジェクトのプロトタイプ上にそのオブジェクトを設置する必要があります。
  3. newキーワードが無いという理由だけで、プロトタイプチェーンから外れてしまうのは、どことなく言語の精神に反します。

終わりに

newキーワードが省略される事によりバグの可能性がもたらされますが、それによりプロトタイプを全く使わないという確かな理由にはなりません。最終的には、アプリケーションの必要性により、どちらの解決法がより良いかが決まってきます。特に大切なのは、オブジェクトの作成に特定のスタイルを選ぶ事、またそのスタイルに固執する事です。