JavaScript

JavaScriptのオブジェクト指向部分のまとめ

仕事上、Javascriptは触りはしますが、しっかりとは勉強してこなかったので
基礎から学習したことを纏めていきます。
今回は、JSのオブジェクト指向周りをまとめていきます。
今ではES2015にてclass構文が追加されていますが、今回は基礎と言う事で、
class構文を使わない旧構文を対象とします。

プロトタイプベースのオブジェクト指向

JavaやC#等の他のオブジェクト指向言語と根本的に異なる点として、JSはプロトタイプベースのオブジェクト指向言語である点が挙げられます。

とりあえず、プロトタイプベースのオブジェクト指向言語の、クラスベースのオブジェクト指向言語と比較しての特徴を挙げると、
・インスタンス化の概念が存在する(こちらはクラスベース同様)
・クラスの概念が存在しない
・プロトタイプの概念が存在する

プロトタイプとは「あるオブジェクトの元となるオブジェクト」であり、JSでは、このプロトタイプを利用して新たなオブジェクトを生成するそう。

JSのクラス宣言

JSは、関数(Functionオブジェクト)にクラスとしての役割を与えており、この関数を便宜的にクラスと呼んでいたりするようです。(そのためJSでいうクラスと、Java等のクラスは完全に同義ではないとか)
他の言語と同様、大文字で始めるのが一般的みたいです。

var User = function() {};

function Book() {};

インスタンス化は、Java等と同様new構文で行います。
new構文なしでも呼び出せるが、その場合関数として呼び出されるので、
下記のコンストラクタ周りで問題が発生します。(詳細は後述します)

var bob = new User();
var dictoinary = new Book();

var jack = User();  // 関数としての呼び出しで、インスタンス化されていない。

コンストラクタの宣言

コンストラクタの宣言方法には、下記のようなものがあります。

// 宣言方法A
function User(name,age) {
    this.name = name;
    this.age = age;
    this.beOld = function() {
        return ++this.age;
    }
};

// 宣言方法B
function Book(title,page) {
    this.title = title;
    this.page = page;
};
Book.prototype = {
    getTitle : function() {
        return this.title;
    }
};

宣言方法Aは、コンストラクタの中にプロパティ(Javaでいうフィールド)とメソッド(値が関数であるプロパティ。役割的にはJavaのメソッドと同様)を宣言しています。
宣言方法Bはコンストラクタ内でプロパティを宣言し、メソッドはprototypeプロパティを利用してプロトタイプオブジェクトに対して追加しています。
宣言方法Bの方がメモリ効率的に良いので推奨されているようです(prototypeプロパティについては後ほど)。

コンストラクタにおけるthis

コンストラクタ内でのthisは、基本的に生成されるインスタンス自身を指します(Java等のthisと同様)
ただし、メソッド内で関数を宣言した場合、関数内のthisは他の関数同様グローバルオブジェクトを指します。

Book.prototype = {
    addVolume : function(volume) {
        // ここのthisはインスタンス自身を指すので正常に通ります
        var newTitle = this.title + " : " + volume;

        function check(result) {
            // ここのthisはグローバルオブジェクトを指すので、存在しないプロパティを指していると言う事でエラーになります。
            if(newTitle.equals(this.title)) {
                this.title = newTitle;
            }
            return this.title;
        }
        return check();
    }
};

ちなみに、new構文無しでコンストラクタを呼び出した場合、コンストラクタは関数として呼び出されるため、コンストラクタ内のthisは
グローバルオブジェクトを指します。

function User(name){
    this.name = name;   
}

var jack = User("jack");
console.log(jack);  // インスタンス -> undefined
console.log(name);  // グローバル変数 -> jack
console.log(jack.name); // インスタンスのプロパティ -> Uncaught TypeError: Cannot read property 'name' of undefined

動的なメソッドの追加

JSでは、生成したインスタンスに対して個別に後からメソッドを追加することができます。

function User(name) {
    this.name = name;
}

var bob = new User("bob");
bob.getName = function() {
    return this.name;
}
console.log(bob.getName()); // "bob"が出力される

var jack = new User("jack");
console.log(jack.getName()); // Uncaught TypeError: jack.getName is not a function

とりあえずここまで。