LoginSignup
7
10

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-09-05

この記事の内容

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

目次

(1) 学習環境の構築と基本的な書き方
(2) 変数とデータ型
(3) 演算子および配列
(4) 制御構文と関数
(5) 関数の応用1
(6) 関数の応用2
(7) オブジェクトの基礎
(8) JavaScriptのオブジェクト指向プログラミング1 概要
(9) JavaScriptのオブジェクト指向プログラミング2 オブジェクトの作り方と継承 <-- この記事の内容
(10) JavaScriptのオブジェクト指向プログラミング3 多態性
(11) JavaScriptのオブジェクト指向プログラミング4 カプセル化
(12) ES6の新機能について

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

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

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

クラス(となるもの)の作り方

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

bs09_01.js
var Dog = function() {

};

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

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

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

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

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

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

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);        // シロ と表示される

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

メソッドの定義

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

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() {
    // 以下に処理を記述する
 }

利用例を、以下に示す。

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 を作って、それを継承する DogCat のオブジェクトを作ってみる。

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() {

}

プロパティの継承

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

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 のコンストラクタを実行している。このように記述することで、namevoice のプロパティを継承することができる。

メソッドの継承

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

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

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();         // タマが鳴く:ニャー! と表示される

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

Dog.prototype = new Animal;

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

次回予告

多態性

7
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
10