読み込み中...

JavaScriptで継承を徹底解説!最強の7つの手法とサンプルコード

JavaScript継承マスターの7の方法のサムネイル画像 JS
この記事は約10分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●JavaScriptの継承について

JavaScriptの継承は、オブジェクト指向プログラミングの基盤となる概念です。

あるオブジェクトが他のオブジェクトのプロパティやメソッドを引き継ぐ仕組みを指します。

JavaScriptでは、クラスベースの継承とプロトタイプベースの継承という2つの方法が存在します。

クラスベースの継承は、ES6で導入されたクラス構文を活用します。

Java、C#などの他のオブジェクト指向言語と類似した概念で、親クラス(スーパークラス)から子クラス(サブクラス)へメソッドやプロパティを受け継ぎます。

一方、プロトタイプベースの継承は、JavaScriptが本来持っている継承の仕組みです。

オブジェクトが他のオブジェクトのプロトタイプオブジェクトを参照することで、プロパティやメソッドを継承します。

継承を理解し、適切に活用することで、コードの再利用性が高まり、保守性も向上します。

効率的な開発を実現するためには、適切な継承方法の選択が欠かせません。

●継承の使い方

JavaScriptの継承には様々な手法があります。

ここでは、7つの異なるアプローチを詳しく解説します。

各手法のメリットやデメリットを理解し、状況に応じて最適な方法を選択できるようになりましょう。

○サンプルコード1:コンストラクタ関数を使った継承

コンストラクタ関数を活用したプロトタイプベースの継承は、JavaScriptの伝統的な手法です。

この方法では、親オブジェクトのプロパティとメソッドを子オブジェクトに引き継ぎます。

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

Animal.prototype.sayName = function() {
  console.log('My name is ' + this.name);
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log('Woof! Woof!');
};

const dog = new Dog('Max', 'Golden Retriever');
dog.sayName(); // My name is Max
dog.bark(); // Woof! Woof!

このコードでは、Animalという親クラスと、それを継承したDogという子クラスを定義しています。

DogクラスはAnimalクラスのプロパティとメソッドを継承しつつ、独自のbarkメソッドを追加しています。

○サンプルコード2:クラスを使った継承

ES6で導入されたクラス構文を用いた継承は、より直感的で読みやすいコードを実現します。

他のオブジェクト指向言語経験者にとっても馴染みやすい方法です。

class Animal {
  constructor(name) {
    this.name = name;
  }

  sayName() {
    console.log('My name is ' + this.name);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  bark() {
    console.log('Woof! Woof!');
  }
}

const dog = new Dog('Max', 'Golden Retriever');
dog.sayName(); // My name is Max
dog.bark(); // Woof! Woof!

クラス構文を使用することで、継承関係がより明確になります。

extendsキーワードを用いてDogクラスがAnimalクラスを継承していることが一目で分かります。

○サンプルコード3:Object.create()を使った継承

Object.create()メソッドを活用したプロトタイプベースの継承は、より柔軟なオブジェクト創造を可能にします。

この方法では、既存のオブジェクトを新しいオブジェクトのプロトタイプとして使用します。

const Animal = {
  init: function(name) {
    this.name = name;
  },
  sayName: function() {
    console.log('My name is ' + this.name);
  }
};

const Dog = Object.create(Animal);
Dog.initDog = function(name, breed) {
  this.init(name);
  this.breed = breed;
};
Dog.bark = function() {
  console.log('Woof! Woof!');
};

const dog = Object.create(Dog);
dog.initDog('Max', 'Golden Retriever');
dog.sayName(); // My name is Max
dog.bark(); // Woof! Woof!

この手法では、Animalオブジェクトを基にしてDogオブジェクトを作成し、さらにそれを基に具体的な犬のインスタンスを生成しています。

階層的なオブジェクト構造を柔軟に構築できる点が特徴です。

○サンプルコード4:プロトタイプチェーンを使った継承

プロトタイプチェーンを直接操作する継承方法は、JavaScriptの内部メカニズムを深く理解するのに役立ちます。

この方法では、子オブジェクトのプロトタイプを親オブジェクトのプロトタイプに直接リンクさせます。

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

Animal.prototype.sayName = function() {
  console.log('My name is ' + this.name);
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Animal.prototype;
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log('Woof! Woof!');
};

const dog = new Dog('Max', 'Golden Retriever');
dog.sayName(); // My name is Max
dog.bark(); // Woof! Woof!

このアプローチでは、Dog.prototypeAnimal.prototypeに直接代入しています。

これにより、DogインスタンスはAnimalのメソッドを直接継承します。

ただし、この方法は親子関係の区別が曖昧になるため、慎重に使用する必要があります。

○サンプルコード5:継承とプライベート変数

JavaScriptにおける継承とプライベート変数の組み合わせは、カプセル化を実現する効果的な方法です。

クロージャを利用して、外部からアクセスできない変数を定義します。

function Animal(name) {
  const _name = name;

  this.getName = function() {
    return _name;
  };
}

function Dog(name, breed) {
  Animal.call(this, name);
  const _breed = breed;

  this.getBreed = function() {
    return _breed;
  };
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

const dog = new Dog('Max', 'Golden Retriever');
console.log(dog.getName()); // Max
console.log(dog.getBreed()); // Golden Retriever

この例では、_name_breedをプライベート変数として定義し、それぞれgetName()getBreed()メソッドを通じてのみアクセス可能にしています。

これにより、データの隠蔽と安全性が向上します。

○サンプルコード6:ミックスインを使った継承

ミックスインを利用した継承は、複数のオブジェクトのプロパティやメソッドを組み合わせる柔軟な方法です。

単一継承の制限を超えて、多様な機能を1つのオブジェクトに統合できます。

const Animal = {
  init: function(name) {
    this.name = name;
  },
  sayName: function() {
    console.log('My name is ' + this.name);
  }
};

const BarkMixin = {
  bark: function() {
    console.log('Woof! Woof!');
  }
};

const Dog = Object.assign({}, Animal, BarkMixin);

const dog = Object.create(Dog);
dog.init('Max');
dog.sayName(); // My name is Max
dog.bark(); // Woof! Woof!

この例では、Object.assign()を使用してAnimalBarkMixinの機能をDogオブジェクトに統合しています。

これにより、Dogは両方のオブジェクトの機能を継承します。

○サンプルコード7:委譲を使った継承

委譲を用いた継承は、他のオブジェクトのメソッドを利用しつつ、柔軟な構造を維持する方法です。

直接的な継承関係を避けつつ、機能を共有できます。

const Animal = {
  init: function(name) {
    this.name = name;
  },
  sayName: function() {
    console.log('My name is ' + this.name);
  }
};

const Dog = {
  init: function(name, breed) {
    Animal.init.call(this, name);
    this.breed = breed;
  },
  bark: function() {
    console.log('Woof! Woof!');
  }
};

Object.setPrototypeOf(Dog, Animal);

const dog = Object.create(Dog);
dog.init('Max', 'Golden Retriever');
dog.sayName(); // My name is Max
dog.bark(); // Woof! Woof!

この例では、DogオブジェクトがAnimalオブジェクトのメソッドを呼び出していますが、直接的な継承関係は最小限に抑えられています。

これにより、オブジェクト間の結合度を低く保ちつつ、機能の再利用が可能になります。

●注意点

JavaScriptの継承を使用する際には、いくつか重要な注意点があります。

これを意識することで、より効果的かつ安全なコードを書くことができます。

プロトタイプチェーンの長さは、パフォーマンスに影響を与える可能性があります。

チェーンが長くなればなるほど、プロパティやメソッドへのアクセス速度が低下する傾向があります。

適切な継承構造を設計し、不必要に深い階層を避けることが大切です。

メソッドのオーバーライドを行う場合、superキーワードを使用して親クラスのメソッドを呼び出すことができます。

これにより、親クラスの機能を拡張しつつ、元の機能も維持することが可能になります。

コンストラクタ関数を継承する場合、call()apply()メソッドを使用して親クラスのコンストラクタを適切に呼び出すことが重要です。

これにより、親クラスで初期化されるべきプロパティが正しく設定されます。

まとめ

JavaScriptの継承は、コードの再利用性と保守性を向上させる重要な概念です。

本記事では、7つの異なる継承手法とそれぞれのサンプルコードを詳しく解説しました。

継承の適切な使用方法を理解し、状況に応じて最適な手法を選択することで、より効率的で柔軟なプログラミングが可能になります。

各手法の特徴と注意点を把握し、実際のプロジェクトに適用していくことで、JavaScriptプログラミングのスキルを大きく向上させることができるでしょう。