JavaScriptのクラスについて興味がありますか?オブジェクト指向プログラミング(OOP)に少し戸惑っていませんか?
もしそうなら、このガイドが役に立つはずです。本記事では、JavaScriptにおけるクラスの仕組みを基礎から解説し、最終的に簡単なToDoアプリを作成するところまでお手伝いします。
JavaScriptにおける関数の基本
JavaScriptプログラミングの基本は「関数」です。最初のプログラムで関数を使うことはほぼ間違いありません。そのため、クラスを学ぶ前に、関数がどのように使われるのかをしっかりと理解しておきましょう。
例えば、ユーザーの名前を表示する関数は次のように書けます。
function greetUser(userName) {
console.log("Hello, " + userName + "!");
}
greetUser("Saka"); // Hello, Saka!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>関数の例</title>
<style>
#output {
font-size: 24px;
color: blue;
}
</style>
</head>
<body>
<div id="output"></div> <!-- メッセージを表示する場所 -->
<script>
function greetUser(userName) {
// HTML要素を操作してメッセージを表示
document.getElementById("output").innerText = "Hello, " + userName + "!";
}
greetUser("Saka"); // 関数を呼び出し
</script>
</body>
</html>
このように関数を使うことで、処理を細かく分割し、再利用性を高めることができます。しかし、アプリケーションが大きくなるにつれて、関数の数が増え、管理が難しくなることがあります。そのため、関数の設計や整理が重要になってきます。
JavaScriptのオブジェクトとは?
オブジェクトはJavaScriptの基本的なデータ構造の一つであり、データとそれに関連する機能をまとめるための方法です。オブジェクトは「プロパティ(属性)」と「メソッド(関数)」で構成されます。
次のようなオブジェクトを作成できます。
const person = {
name: "Saka",
greet: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
person.greet(); // Hello, my name is Saka
ここで使用されているthis
キーワードは、オブジェクト内からそのオブジェクト自身のプロパティにアクセスするために使われます。
この例では、this.name
がperson
オブジェクトのname
プロパティ("Saka"
)を参照しています。
しかし、同じようなオブジェクトを複数作成する場合、手作業で一つずつオブジェクトを定義するのは非効率的です。そこで、コンストラクタ関数やクラスを使うことで、効率的にオブジェクトを作成できます。
コンストラクタ関数:オブジェクトを作成する設計図
コンストラクタ関数を使った例を以下に示します。
// コンストラクタ関数
function Person(name) {
this.name = name;
this.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
}
// オブジェクトの作成
const person1 = new Person("Saka");
const person2 = new Person("Tomato");
person1.greet(); // Hello, my name is Saka
person2.greet(); // Hello, my name is Tomato
このように、コンストラクタ関数を使うことで、同じ構造を持つオブジェクトを簡単に複数作成できます。
ES6クラス:より簡潔な記法
ES6以降ではclass
構文を使うことで、オブジェクト指向のコードをよりシンプルに書けるようになりました。
以下は、クラスを使った基本的な例です。
// クラスを使った例
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
const person1 = new Person("Saka");
person1.greet(); // Hello, my name is Saka
このように、class
構文を使うことで、コンストラクタやメソッドを明確に定義でき、コードの可読性が向上します。
クラスの継承
さらに、extends
キーワードを使うことで、既存のクラスを継承し、新しいクラスを作成できます。
以下は、Person
クラスを継承してDeveloper
クラスを作成する例です。
// Personクラスを先に定義
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
// Developerクラスを定義
class Developer extends Person {
constructor(name, language) {
super(name); // 親クラスのコンストラクタを呼び出す
this.language = language;
}
code() {
console.log(`${this.name} is coding in ${this.language}`);
}
}
const developer1 = new Developer("Saka", "JavaScript");
developer1.greet(); // Hello, my name is Saka
developer1.code(); // Saka is coding in JavaScript
ファイルが正しく読み込まれているか確認します。以下はHTMLファイルでの読み込み例です。
HTMLファイル
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>クラスの例</title>
</head>
<body>
<script src="person.js"></script> <!-- Personクラスが定義されたファイル -->
<script src="developer.js"></script> <!-- Developerクラスが定義されたファイル -->
<script src="main.js"></script> <!-- クラスを使用するファイル -->
</body>
</html>
person.js
(Personクラスの定義)
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
developer.js
(Developerクラスの定義)
class Developer extends Person {
constructor(name, language) {
super(name);
this.language = language;
}
code() {
console.log(`${this.name} is coding in ${this.language}`);
}
}
main.js
(クラスを使用)
const developer1 = new Developer("Saka", "JavaScript");
developer1.greet(); // Hello, my name is Saka
developer1.code(); // Saka is coding in JavaScript
モジュールを使用している場合
ES6モジュール(import
/export
)を使用している場合、クラスをエクスポートし、インポートする必要があります。
▸person.js
(Personクラスのエクスポート)
export class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
▸developer.js
(Developerクラスのエクスポート)
import { Person } from './person.js';
export class Developer extends Person {
constructor(name, language) {
super(name);
this.language = language;
}
code() {
console.log(`${this.name} is coding in ${this.language}`);
}
}
▸main.js
(クラスのインポートと使用)
import { Developer } from './developer.js';
const developer1 = new Developer("Saka", "JavaScript");
developer1.greet(); // Hello, my name is Saka
developer1.code(); // Saka is coding in JavaScript
▸HTMLファイル(モジュールを使用する場合)
<script type="module" src="main.js"></script>
プロトタイプとメモリ効率の向上
JavaScriptでは、プロトタイプを活用することで、各オブジェクトに重複するメソッドを持たせずに済みます。これにより、メモリ効率が向上します。以下は、プロトタイプを使ってメソッドを共有する例です。
function Person(name) {
this.name = name;
}
// プロトタイプにメソッドを追加
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
const alice = new Person("Saka");
alice.greet(); // Hello, I'm Saka
このように、greet
メソッドをPerson.prototype
に追加することで、すべてのPerson
オブジェクトが同じgreet
メソッドを共有できます。これにより、メモリ使用量が削減され、パフォーマンスが向上します。
継承:一つのクラスから別のクラスを派生させる
JavaScriptでは、call()
とObject.create()
を使って、簡単にクラスを継承できます。
以下は、Person
クラスを継承してDeveloper
クラスを作成する例です。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
// DeveloperクラスをPersonクラスから継承
function Developer(name, language) {
// Personのコンストラクタを呼び出す
Person.call(this, name);
this.language = language;
}
// DeveloperのプロトタイプをPersonのプロトタイプにリンク
Developer.prototype = Object.create(Person.prototype);
// Developerのメソッドを追加
Developer.prototype.code = function() {
console.log(`${this.name} is coding in ${this.language}`);
};
const Saka = new Developer("Saka", "JavaScript");
Saka.greet(); // Hello, I'm Saka
Saka.code(); // Saka is coding in JavaScript
Person.call(this, name)
:Person
クラスのコンストラクタを呼び出し、Developer
オブジェクトにname
プロパティを設定します。
Object.create(Person.prototype)
:Developer
のプロトタイプをPerson
のプロトタイプにリンクし、Person
のメソッドを継承します。
- メソッドの追加:
Developer
クラスに独自のメソッド(code
)を追加できます。
- プロトタイプチェーン:
- JavaScriptのオブジェクトは、プロトタイプチェーンを通じてメソッドやプロパティを継承します。これにより、メモリ効率が向上し、コードの再利用性が高まります。
- ES6クラスとの比較:
- ES6の
class
構文を使うと、プロトタイプベースの継承をより直感的に記述できます。以下は、同じ内容をclass
構文で書いた例です。
- ES6の
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, I'm ${this.name}`);
}
}
class Developer extends Person {
constructor(name, language) {
super(name);
this.language = language;
}
code() {
console.log(`${this.name} is coding in ${this.language}`);
}
}
const Saka = new Developer("Saka", "JavaScript");
Saka.greet(); // Hello, I'm Saka
Saka.code(); // Saka is coding in JavaScript
クラスを活用したToDoアプリの作成
クラスを活用することで、小規模なアプリケーションも整理して実装できます。たとえば、ToDoアプリを作るのに適した設計として ToDo
クラスと ToDoList
クラスがあります。
class ToDo {
constructor(description) {
this.description = description;
this.completed = false;
}
markComplete() {
this.completed = true;
console.log(`"${this.description}" marked as complete!`);
}
}
さらに、ToDoのリストを管理するための ToDoList
クラスも作成できます。
class ToDoList {
constructor() {
this.todos = [];
}
addTodo(description) {
const newTodo = new ToDo(description);
this.todos.push(newTodo);
}
listTodos() {
return this.todos;
}
}
その後、HTMLと連携させることで、ブラウザ上で動作するToDoアプリを作成できます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDoアプリ</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div>
<h1>ToDoアプリ</h1>
<input type="text" id="todoInput" placeholder="新しいToDoを入力">
<button id="addButton">Add To-Do</button>
<ul id="todoList"></ul>
</div>
<script>
class ToDo {
constructor(description) {
this.description = description;
this.completed = false;
}
markComplete() {
this.completed = true;
console.log(`"${this.description}" marked as complete!`);
}
}
class ToDoList {
constructor() {
this.todos = [];
}
addTodo(description) {
const newTodo = new ToDo(description);
this.todos.push(newTodo);
this.updateUI();
}
listTodos() {
return this.todos;
}
updateUI() {
const todoListElement = document.getElementById("todoList");
todoListElement.innerHTML = ""; // リストをクリア
this.todos.forEach((todo, index) => {
const li = document.createElement("li");
li.textContent = todo.description;
if (todo.completed) {
li.classList.add("completed");
}
li.addEventListener("click", () => {
todo.markComplete();
this.updateUI();
});
todoListElement.appendChild(li);
});
}
}
const myTodoList = new ToDoList();
document.getElementById("addButton").addEventListener("click", () => {
const desc = document.getElementById("todoInput").value;
if (desc) {
myTodoList.addTodo(desc);
document.getElementById("todoInput").value = ""; // 入力ボックスをクリア
}
});
</script>
</body>
</html>
ブラウザでhtmlファイルを開きます。
アプリの使用
テキストボックスにToDoを入力し、「Add To-Do」ボタンをクリックすると、ToDoがリストに追加されます。
リストの項目をクリックすると、そのToDoが完了済みとしてマークされ、文字に取り消し線が引かれます。
説明
▸ToDoクラス: 各ToDoアイテムを表します。description(説明)とcompleted(完了済みかどうか)のプロパティを持ちます。
▸ToDoListクラス: ToDoアイテムのリストを管理します。addTodoメソッドで新しいToDoを追加し、updateUIメソッドでUIを更新します。
▸HTML: ユーザーがToDoを入力し、追加するためのインターフェースを提供します。
▸JavaScript: ユーザーの操作に応じてToDoリストを更新し、UIに反映します。
これで、ブラウザ上で動作するシンプルなToDoアプリが完成します。
まとめ
JavaScriptのクラスは、オブジェクト指向プログラミング(OOP)の原則を取り入れながら、より読みやすく、管理しやすいコードを書くための優れた手段です。
クラスを使うことで、関連するデータと機能を一箇所にまとめ、コードの再利用性や保守性を高めることができます。
さらに、プロトタイプを理解することで、クラスが内部的にどのように動作しているのかをより深く理解できます。プロトタイプを活用することで、メモリ効率を向上させ、すべてのインスタンスが同じメソッドを共有できるようになります。
- クラスとプロトタイプの関係:
- ES6の
class
構文は、内部的にはプロトタイプベースの継承を使用しています。そのため、クラスを使いながらも、プロトタイプの仕組みを理解しておくことが重要です。
- ES6の
- OOPの原則:
- カプセル化、継承、ポリモーフィズムといったOOPの原則をJavaScriptのクラスで実現できます。
以下のリンクでは、JavaScriptに関する記事をまとめています。各記事をクリックして、詳しい情報をご確認ください。
- JavaScriptのクラスを基礎から学ぶ初心者向けガイド
- Node.jsを最新バージョンにアップグレードする方法(3つ)
- Next.js 使い方
- Viteではじめるフロントエンド開発:ビルドからデプロイまで解説
- TypeScript入門ガイド:基本から実践まで型安全な開発の始め方
- jQuery入門:初心者のための基本的な使い方と実践テクニック
- Reactの基礎から環境構築まで:初心者向け完全ガイド
- JavaScriptで実現する15の実用的なコード例:結果付き完全版
- HTMLとJavaScriptの融合:効率的な読み込みと呼び出しテクニック
- Python、JavaScriptを実行する基本的な方法
- Node.jsのインストール方法から簡単な使用例まで