この記事では、オブジェクト指向プログラミングのクラスの定義方法、カプセル化、継承、モジュールの使用方法、そしてオブジェクト指向構文の高度なテーマについて、具体的なコード例を交えて理解を深めることができます。これらの知識は、効果的なオブジェクト指向プログラミングの基礎となります。
はじめに
この記事のコードをコピペして出力してみよう。
VSCodeでコードを書き、Node.jsでコンソール出力する方法がおすすめです。
クラスの基本
クラスは、オブジェクトの設計図や雛形のようなものです。クラスを使うことで、同じ構造や振る舞いを持つオブジェクトを簡単に作成できます。
// Personクラスの定義
class Person {
// コンストラクタ(オブジェクト生成時に呼ばれる)
constructor(name, age) {
this.name = name;
this.age = age;
}
// メソッド
introduce() {
console.log(`私の名前は${this.name}で、${this.age}歳です。`);
}
}
// Personクラスのインスタンスを作成
const person1 = new Person("太郎", 30);
person1.introduce(); // 出力: 私の名前は太郎で、30歳です。
出力結果:
私の名前は太郎で、30歳です。
このコードでは、Person
クラスを定義しています。constructor
メソッドはオブジェクトの初期化を行い、introduce
メソッドは自己紹介文を出力します。new
キーワードを使ってクラスのインスタンスを作成し、そのメソッドを呼び出しています。
コードの解説
クラスの定義:
class Person {
// クラスの内容
}
class
キーワードを使用してPerson
クラスを定義しています。- クラスは、オブジェクトの設計図やテンプレートのようなものです。
コンストラクタの定義:
constructor(name, age) {
this.name = name;
this.age = age;
}
constructor
はクラスのインスタンスが作成されるときに自動的に呼び出される特別なメソッドです。name
とage
はコンストラクタのパラメータです。this
は、作成されるインスタンス自身を指します。this.name = name
とthis.age = age
で、インスタンスのプロパティを初期化しています。
メソッドの定義:
introduce() {
console.log(`私の名前は${this.name}で、${this.age}歳です。`);
}
introduce
はクラスのメソッド(関数)です。- このメソッドは、インスタンスの
name
とage
を使用して自己紹介文を出力します。 ${}
はテンプレートリテラルで、文字列内に変数を埋め込むために使用されます。
クラスのインスタンス化:
const person1 = new Person("太郎", 30);
new
キーワードを使用して、Person
クラスの新しいインスタンスを作成しています。"太郎"
と30
がコンストラクタに渡される引数です。- 作成されたインスタンスは
person1
変数に代入されます。
メソッドの呼び出し:
person1.introduce();
person1
インスタンスのintroduce
メソッドを呼び出しています。- これにより、コンソールに自己紹介文が出力されます。
重要なポイント:
- クラスは、オブジェクト指向プログラミングの基本的な構成要素です。
- コンストラクタは、新しいインスタンスの初期化を担当します。
- メソッドは、クラスのインスタンスが持つ機能(関数)です。
this
キーワードは、現在のインスタンスを参照するために使用されます。- インスタンス化は、クラスの設計図を基に実際のオブジェクトを作成するプロセスです。
このコードは、JavaScriptにおけるクラスの基本的な構造と使用方法を示しています。クラスを使用することで、関連するデータ(プロパティ)と機能(メソッド)をカプセル化し、コードの構造化と再利用性を向上させることができます。
カプセル化
カプセル化は、オブジェクトの内部データを外部から直接アクセスできないようにし、メソッドを通じてのみ操作可能にする概念です。JavaScriptでは、慣習的に_(アンダースコア)をプレフィックスとして使用して、プライベートなプロパティやメソッドを表現します。
class BankAccount {
constructor(initialBalance) {
this._balance = initialBalance; // プライベートプロパティ
}
// 残高を取得するメソッド
getBalance() {
return this._balance;
}
// 預金するメソッド
deposit(amount) {
if (amount > 0) {
this._balance += amount;
console.log(`${amount}円預金しました。残高: ${this._balance}円`);
}
}
// 引き出すメソッド
withdraw(amount) {
if (amount > 0 && amount <= this._balance) {
this._balance -= amount;
console.log(`${amount}円引き出しました。残高: ${this._balance}円`);
} else {
console.log("引き出しできません。");
}
}
}
const account = new BankAccount(1000);
account.deposit(500); // 出力: 500円預金しました。残高: 1500円
account.withdraw(200); // 出力: 200円引き出しました。残高: 1300円
console.log(account.getBalance()); // 出力: 1300
出力結果:
500円預金しました。残高: 1500円
200円引き出しました。残高: 1300円
1300
このコードでは、BankAccount
クラスが銀行口座を表現しています。残高(_balance
)は直接アクセスできないようにし、deposit
やwithdraw
メソッドを通じてのみ操作可能にしています。
コードの解説
クラスの定義:
class BankAccount {
// クラスの内容
}
BankAccount
クラスを定義しています。このクラスは銀行口座を表現します。
コンストラクタ:
constructor(initialBalance) {
this._balance = initialBalance; // プライベートプロパティ
}
constructor
はクラスのインスタンスが作成されるときに呼び出されます。initialBalance
は初期残高を表すパラメータです。- this._balance は残高を保持するプロパティです。
- 先頭の _ はこのプロパティがプライベートであることを示す慣習です(実際には完全にプライベートではありません)。
残高取得メソッド:
getBalance() {
return this._balance;
}
getBalance
メソッドは現在の残高を返します。- これはカプセル化の一例で、プライベートな _balance にアクセスする方法を提供します。
預金メソッド:
deposit(amount) {
if (amount > 0) {
this._balance += amount;
console.log(`${amount}円預金しました。残高: ${this._balance}円`);
}
}
deposit
メソッドは指定された金額を残高に追加します。amount > 0
のチェックは、正の金額のみを受け入れるバリデーションです。
引き出しメソッド:
withdraw(amount) {
if (amount > 0 && amount <= this._balance) {
this._balance -= amount;
console.log(`${amount}円引き出しました。残高: ${this._balance}円`);
} else {
console.log("引き出しできません。");
}
}
withdraw
メソッドは指定された金額を残高から引き出します。- 条件文は、金額が正で、かつ現在の残高以下であることを確認します。
クラスのインスタンス化と使用:
const account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
console.log(account.getBalance());
new BankAccount(1000)
で1000円の初期残高を持つ新しい口座を作成します。deposit
とwithdraw
メソッドを呼び出して、預金と引き出しを行います。getBalance
メソッドで最終的な残高を取得し、表示します。
重要なポイント:
- カプセル化:
_balance
は直接アクセスされず、メソッドを通じて操作されます。 - メソッド: クラス内の関数で、オブジェクトの振る舞いを定義します。
- 条件文: メソッド内で使用され、不正な操作を防ぎます。
- テンプレートリテラル:
`
を使用し、文字列内に変数を埋め込みます。
このコードは、オブジェクト指向プログラミングの基本的な概念(カプセル化、メソッド、プロパティ)を示しています。BankAccount
クラスは、実際の銀行口座の基本的な機能をモデル化しており、データ(残高)と操作(預金、引き出し)を一つのユニットにまとめています。
継承
継承は、既存のクラスを基に新しいクラスを作成する機能です。親クラスの機能を引き継ぎつつ、新しい機能を追加したり既存の機能を上書きしたりできます。
// 親クラス
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}が鳴いています。`);
}
}
// 子クラス
class Dog extends Animal {
constructor(name, breed) {
super(name); // 親クラスのコンストラクタを呼び出す
this.breed = breed;
}
speak() {
console.log(`${this.name}が吠えています:ワンワン!`);
}
fetch() {
console.log(`${this.name}がボールを取ってきました。`);
}
}
const animal = new Animal("動物");
animal.speak(); // 出力: 動物が鳴いています。
const dog = new Dog("ポチ", "柴犬");
dog.speak(); // 出力: ポチが吠えています:ワンワン!
dog.fetch(); // 出力: ポチがボールを取ってきました。
出力結果:
動物が鳴いています。
ポチが吠えています:ワンワン!
ポチがボールを取ってきました。
この例では、Animal
クラスを親クラスとし、Dog
クラスがそれを継承しています。Dog
クラスはAnimal
クラスのspeak
メソッドをオーバーライド(上書き)し、新しいfetch
メソッドを追加しています。
コードの解説
親クラス(基底クラス)の定義:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}が鳴いています。`);
}
}
Animal
は親クラス(基底クラス)です。constructor
でname
プロパティを初期化します。speak
メソッドは動物が鳴く動作を表現します。
子クラス(派生クラス)の定義:
class Dog extends Animal {
// クラスの内容
}
extends
キーワードを使用して、Dog
クラスがAnimal
クラスを継承していることを示します。Dog
はAnimal
の全てのプロパティとメソッドを継承します。
子クラスのコンストラクタ:
constructor(name, breed) {
super(name); // 親クラスのコンストラクタを呼び出す
this.breed = breed;
}
super(name)
は親クラス(Animal
)のコンストラクタを呼び出します。this.breed = breed
でDog
クラス特有のbreed
プロパティを追加しています。
メソッドのオーバーライド:
speak() {
console.log(`${this.name}が吠えています:ワンワン!`);
}
Dog
クラスでspeak
メソッドを再定義(オーバーライド)しています。- これにより、
Dog
インスタンスのspeak
メソッドは親クラスの同名メソッドを上書きします。
子クラス固有のメソッド:
fetch() {
console.log(`${this.name}がボールを取ってきました。`);
}
fetch
メソッドはDog
クラス特有のメソッドです。
インスタンスの作成と使用:
const animal = new Animal("動物");
animal.speak(); // 出力: 動物が鳴いています。
const dog = new Dog("ポチ", "柴犬");
dog.speak(); // 出力: ポチが吠えています:ワンワン!
dog.fetch(); // 出力: ポチがボールを取ってきました。
Animal
とDog
クラスのインスタンスを作成しています。- それぞれのインスタンスでメソッドを呼び出しています。
重要なポイント:
- 継承: 子クラスは親クラスの特性を引き継ぎます。
super
: 親クラスのコンストラクタやメソッドを呼び出すために使用します。- メソッドのオーバーライド: 子クラスで親クラスのメソッドを再定義できます。
- ポリモーフィズム: 同じメソッド名(
speak
)でも、クラスによって異なる動作をします。
このコードは、オブジェクト指向プログラミングの重要な概念である継承とポリモーフィズムを示しています。Dog
クラスは Animal
クラスを継承することで基本的な特性を受け継ぎつつ、独自の特性や振る舞いを追加・変更しています。これにより、コードの再利用性と拡張性が向上します。
モジュール
モジュールは、コードを機能単位で分割し、再利用性を高めるための仕組みです。ES6以降のJavaScriptでは、export
とimport
を使ってモジュールを定義し、利用することができます。
※Node.jsでES Modulesを使用するには、以下の「package.json」ファイルをプロジェクトのルートディレクトリに追加してください。コードは以下の内容をコピペしてください。
package.json
{
"type": "module"
}
「package.json」ファイルがない場合は以下のエラーが出ます。
(node:23000) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
エラー内容:ES モジュールをロードするには、package.json で “type”: “module” を設定するか、.mjs 拡張子を使用するように警告がでます。
※ブラウザでES Modulesを使用するには、スクリプトタグにtype="module"
属性を追加する必要があります。
<script type="module" src="main.js"></script>
math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
main.js
import { add, subtract } from './math.js';
console.log(add(5, 3)); // 出力: 8
console.log(subtract(10, 4)); // 出力: 6
出力結果:
8
6
この例では、math.js
ファイルで数学関連の関数をエクスポートし、main.js
ファイルでそれらをインポートして使用しています。
math.jsの解説
関数のエクスポート:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export
キーワードを使用して、関数を他のファイルから利用可能にしています。add
関数は2つの数値を足し合わせます。subtract
関数は1つの数値から別の数値を引きます。
main.jsの解説
モジュールのインポート:
import { add, subtract } from './math.js';
import
文を使用して、別のファイル(ここでは'./math.js'
)からエクスポートされた関数をインポートしています。{ add, subtract }
は、インポートする特定の関数を指定しています(名前付きインポート)。'./math.js'
は、インポート元のファイルパスを示しています。
インポートした関数の使用:
console.log(add(5, 3)); // 出力: 8
console.log(subtract(10, 4)); // 出力: 6
- インポートした
add
とsubtract
関数を使用しています。 - 結果をコンソールに出力しています。
重要なポイント:
- モジュール: JavaScriptのモジュールシステムを使用しています。これにより、コードを別々のファイルに分割し、必要な部分だけをインポートできます。
- エクスポート (
export
): 関数、オブジェクト、プリミティブ値などを他のモジュールで使用できるようにします。 - インポート (
import
): 他のモジュールからエクスポートされたものを現在のモジュールで使用できるようにします。 - 名前付きエクスポート/インポート:
{ }
を使用して特定の項目をエクスポート/インポートします。 - ファイルパス:
'./math.js'
の./
は現在のディレクトリを示します。
注意点:
- このコードを実行するには、モジュールをサポートする環境(最新のブラウザ、Node.js、またはモジュールバンドラー)が必要です。
- HTMLファイルで使用する場合、
<script>
タグにtype="module"
属性を追加する必要があります。
このコードは、JavaScriptのモジュールシステムの基本的な使用方法を示しています。モジュールを使用することで、コードを整理し、再利用性を高め、名前空間の衝突を避けることができます。これは大規模なアプリケーションやライブラリの開発において特に重要です。
オブジェクト指向構文の高度な機能
オブジェクト指向プログラミングには、さらに高度な機能があります。
- 静的メソッドとプロパティ: クラスのインスタンスを作成せずに使用できるメソッドやプロパティ。
- ゲッターとセッター: プロパティの読み取りや設定をカスタマイズする特殊なメソッド。
- 抽象クラスとインターフェース: 直接インスタンス化できない基底クラスや、メソッドの実装を強制する仕組み。
class MathOperations {
static PI = 3.14159; // 静的プロパティ
static circleArea(radius) { // 静的メソッド
return this.PI * radius * radius;
}
constructor(value) {
this._value = value;
}
get value() { // ゲッター
return this._value;
}
set value(newValue) { // セッター
if (newValue >= 0) {
this._value = newValue;
}
}
}
console.log(MathOperations.PI); // 出力: 3.14159
console.log(MathOperations.circleArea(5)); // 出力: 78.53975
const math = new MathOperations(10);
console.log(math.value); // 出力: 10
math.value = 20;
console.log(math.value); // 出力: 20
出力結果:
3.14159
78.53975
10
20
このコードでは、静的プロパティ・メソッド、そしてゲッターとセッターの使用例を示しています。静的メンバーはクラス自体に属し、インスタンス化せずに使用できます。ゲッターとセッターは、プロパティのアクセスや変更時の振る舞いをカスタマイズするのに役立ちます。
コードの解説
クラスの定義:
class MathOperations {
// クラスの内容
}
MathOperations
クラスを定義しています。
静的プロパティ:
static PI = 3.14159;
static
キーワードを使用して、クラスレベルのプロパティを定義しています。- この
PI
はインスタンスを作成せずに直接クラス名でアクセスできます。
静的メソッド:
static circleArea(radius) {
return this.PI * radius * radius;
}
static
キーワードを使用して、クラスレベルのメソッドを定義しています。- このメソッドもインスタンスを作成せずに直接クラス名で呼び出せます。
コンストラクタ:
constructor(value) {
this._value = value;
}
- クラスのインスタンスを作成する際に呼び出される特別なメソッドです。
_value
はプライベートプロパティを示す慣習的な命名です(実際には完全にプライベートではありません)。
ゲッター(Getter):
get value() {
return this._value;
}
get
キーワードを使用して、プロパティの値を取得するメソッドを定義しています。- これにより、
math.value
のようにプロパティとしてアクセスできます。
セッター(Setter):
set value(newValue) {
if (newValue >= 0) {
this._value = newValue;
}
}
set
キーワードを使用して、プロパティの値を設定するメソッドを定義しています。- 条件文を使用して、負の値が設定されるのを防いでいます。
静的メンバーの使用:
console.log(MathOperations.PI);
console.log(MathOperations.circleArea(5));
- 静的プロパティとメソッドは、クラス名を使って直接アクセス・呼び出しができます。
インスタンスの作成と使用:
const math = new MathOperations(10);
console.log(math.value);
math.value = 20;
console.log(math.value);
new
キーワードを使ってクラスのインスタンスを作成しています。- ゲッターとセッターを使ってプロパティにアクセスしています。
重要なポイント:
- 静的メンバー: クラスレベルで存在し、インスタンス化せずに使用できます。
- ゲッター/セッター: プロパティのように見えますが、実際はメソッドです。これにより、値の取得や設定時に追加のロジックを実行できます。
- カプセル化: ゲッターとセッターを使用することで、内部データ(
_value
)へのアクセスを制御しています。
このコードは、JavaScriptのクラスにおける高度な機能を示しています。静的メンバー、ゲッター、セッターの使用により、より柔軟で安全なクラス設計が可能になります。これらの機能は、オブジェクト指向プログラミングの重要な概念であるカプセル化とデータ隠蔽を実現するのに役立ちます。
以上が、JavaScriptのオブジェクト指向構文の基本と応用についての解説です。これらの概念を理解し適切に使用することで、より構造化され、保守性の高いコードを書くことができます。
まとめ
- クラスの基本:クラスの定義方法、メンバ変数とメソッドの宣言について
- カプセル化:データの隠蔽とアクセス制御の重要性
- 継承:クラス間の階層関係と機能の再利用方法
- モジュール:関連する機能をグループ化する方法
- オブジェクト指向構文の高度な機能:より複雑なオブジェクト指向プログラミングの概念
この記事で学んだ知識を活用することで、オブジェクト指向プログラミングのスキルが大幅に向上し、より効果的で保守性の高いコードを書くことができるようになります。クラスの基本から高度な概念まで理解することは、現代のソフトウェア開発において不可欠なスキルです。
コメント