JavaScript文法(9) JavaScriptのオブジェクト指向プログラミング2 オブジェクトの作り方と継承

# この記事の内容

* 独自なオブジェクト（他言語のclassに相当するもの）の作り方
* オブジェクト指向プログラミングにおける「継承」をJavaScriptではどのようにするか

# 目次

(1) [学習環境の構築と基本的な書き方](http://qiita.com/azk0305/items/a13d494178d83fc8f2bc)
(2) [変数とデータ型](http://qiita.com/azk0305/items/d78d744dff9656b22dd0)
(3) [演算子および配列](http://qiita.com/azk0305/items/748f4afadcfa5350a552)
(4) [制御構文と関数](http://qiita.com/azk0305/items/ed943040a8f7140d5a48)
(5) [関数の応用1](http://qiita.com/azk0305/items/f7e0653b20425fdb9f1b)
(6) [関数の応用2](http://qiita.com/azk0305/items/0fd54f9c66f726443dd6)
(7) [オブジェクトの基礎](http://qiita.com/azk0305/items/0d2018a1c6e547b7f65a)
(8) [JavaScriptのオブジェクト指向プログラミング1 概要](http://qiita.com/azk0305/items/1e1bd10522927eaddd6a)
(9) JavaScriptのオブジェクト指向プログラミング2 オブジェクトの作り方と継承 **<-- この記事の内容**
(10) [JavaScriptのオブジェクト指向プログラミング3 多態性](http://qiita.com/azk0305/items/1c713562f6f842dcf1dc)
(11) [JavaScriptのオブジェクト指向プログラミング4 カプセル化](http://qiita.com/azk0305/items/914f6e447b41d4ced25e)
(12) [ES6の新機能について](http://qiita.com/azk0305/items/ebfb43c088101f7138f9)

# 独自なオブジェクトの作り方

前回の内容のように、 *ES5までの* JavaScriptでは、classというキーワードが存在しない。既に用意されているオブジェクトを受け継いで新しいオブジェクトを作る形になる。

組み込みオブジェクトという、JavaScriptで最初から用意されているオブジェクトの使い方を前回の記事で観てきた。今回は、独自なオブジェクトを作る方法について観ていく。

## クラス（となるもの）の作り方

7回目の記事の内容どおりにコーディングしても構わないが、よりオブジェクト指向プログラミングらしく記述する方法として、**クラスに該当するオブジェクト（いわば、見本となるオブジェクト）を `function` で定義してしまう**、という方法がある。

```js:bs09_01.js
var Dog = function() {
  
};

var pochi = new Dog();
var shiro = new Dog();
```

上記の例は、 `Dog` というクラス（見本のオブジェクト）を作ったことになる。この `Dog` オブジェクトを見本として、 `pochi` と `shiro` いうオブジェクトを生成している。Javaでいうところの、

```java
Dog pochi = new Dog();
Dog shiro = new Dog();
```

これを実行したようなものである。

## プロパティの定義とコンストラクタ（となるもの）の利用

オブジェクトの特徴のうち、プロパティにあたるものの初期値の設定には、 `this` キーワードを利用する。

```js:bs09_01.js（追記版）
var Dog = function(name) {
  this.name = name;
};

var pochi = new Dog('ポチ');
var shiro = new Dog('シロ');

console.log(pochi.name);        // ポチ と表示される
console.log(shiro.name);        // シロ と表示される
```

`Dog` に `name` （名前）の属性を追加し、 `pochi` には「ポチ」という名前をつけている。このように、functionの引数に値を与えて、 `this` キーワードでプロパティを設定することができる。このような方法によるプロパティの設定は、いうなれば「コンストラクタ」である。

## メソッドの定義

`Dog` に `bark` というメソッドを追加してみる。メソッドも同じように `this.メソッド名 = function() {...}` と記述して指定することができる。

```js
var Dog = function(name) {
  this.name = name;
  this.bark = function() {
    console.log(this.name + "が吠える：ワン！");
  };
};

var pochi = new Dog('ポチ');
var shiro = new Dog('シロ');

pochi.bark();                   // ポチが吠える：ワン！ と表示される
shiro.bark();                   // シロが吠える：ワン！ と表示される
```

この他に、もうひとつ、メソッドを定義する方法がある。それは、見本オブジェクトがもつ `prototype` というプロパティを利用する。

```
（見本の）オブジェクト名.prototype.メソッド名() = function() {
    // 以下に処理を記述する
 }
```

利用例を、以下に示す。

```js:bs09_01.js（追記版）
var Dog = function(name) {
  this.name = name;
};

Dog.prototype.bark = function() {
  console.log(this.name + "が吠える：ワン！");
}

var pochi = new Dog('ポチ');
var shiro = new Dog('シロ');

console.log(pochi.name);        // ポチ と表示される
console.log(shiro.name);        // シロ と表示される

pochi.bark();                   // ポチが吠える：ワン！ と表示される
shiro.bark();                   // シロが吠える：ワン！ と表示される
```

メソッドの定義は、このようにして行う。

※なお、`prototype` でプロパティを設定することも可能。サンプルコードは省略。

# 継承

オブジェクト指向プログラミングにおける3つの特徴として、以下のものがある。

* 継承（Inheritance）
* 多態性（Polymorphism）
* カプセル化（Encapsulation）

以降、これらをJavaScriptでどのように記述すれば実現できるかを観ていく。まずは継承。

先ほどは `Dog` という見本オブジェクトを作成したが、もう少し抽象的な見本オブジェクトとして `Animal` を作って、それを継承する `Dog` と `Cat` のオブジェクトを作ってみる。

```js:bs09_02.js
var Animal = function(name, voice) {
  this.name  = name;
  this.voice = voice;
}
Animal.prototype.bark = function() {
  console.log(this.name + "が鳴く：" + this.voice);
}

var Dog = function() {
  
}

var Cat = function() {
  
}
```

## プロパティの継承

`Animal` は `name` （名前）と `voice` （鳴き声）のプロパティを持っているとする。このとき `Dog` や `Cat` が `Animal` を継承して、この2つのプロパティを持たせたい場合、以前の記事で紹介した `call` もしくは `apply` のメソッドを利用する。おさらいすると、どちらのメソッドも、引数で指定したオブジェクトに、自分が持っているメソッドを貸し出して、すぐ実行してもらうというものである。

```js:bs09_02.js（追記版）
var Animal = function(name, voice) {
  this.name  = name;
  this.voice = voice;
}
Animal.prototype.bark = function() {
  console.log(this.name + "が鳴く：" + this.voice);
}

var Dog = function(name) {
  Animal.call(this, name, "ワン！");
}

var Cat = function(name) {
  Animal.call(this, name, "ニャー！");
}

var pochi = new Dog("ポチ");
var tama  = new Cat("タマ");

console.log(pochi.name);        // ポチ と表示される
console.log(tama.name);         // タマ と表示される
```

`Dog` および `Cat` のコンストラクタ部分で `Animal` オブジェクトの `call` メソッドを実行し、`Animal` のコンストラクタを実行している。このように記述することで、`name` と `voice` のプロパティを継承することができる。

## メソッドの継承

では、JavaScriptでメソッドの継承を実現するにはどうするかというと、**プロトタイプチェーン**というものを利用する。プロトタイプチェーンは、プロトタイプを次々にさかのぼって参照・実行することが出来る仕組みである。

つまり、`Dog` や `Cat` それぞれで、プロトタイプに `Animal`のプロトタイプを指定してあげれば良い。

```js:bs09_02.js（追記版）
var Animal = function(name, voice) {
  this.name  = name;
  this.voice = voice;
}
Animal.prototype.bark = function() {
  console.log(this.name + "が鳴く：" + this.voice);
}

var Dog = function(name) {
  Animal.call(this, name, "ワン！");
}
Dog.prototype = new Animal;

var Cat = function(name) {
  Animal.call(this, name, "ニャー！");
}
Cat.prototype = new Animal;

var pochi = new Dog("ポチ");
var tama  = new Cat("タマ");

pochi.bark();        // ポチが鳴く：ワン！   と表示される
tama.bark();         // タマが鳴く：ニャー！ と表示される
```

プロトタイプの指定は、上記のコードでは、この部分。

```js
Dog.prototype = new Animal;
```

`子供のオブジェクト名.prototype = new 親のオブジェクト名;` と記載する（親のオブジェクト名の後ろに括弧は不要）。こうすることで、`Dog` にわざわざ `bark` メソッドの定義を記述しなくても、親である `Animal` のプロトタイプにさかのぼって内容を参照し、`bark` メソッドが実行される。

# 次回予告

多態性