JavaScriptのクラスは、オブジェクトを作るための設計図のようなものです。JavaScriptで少し大きなプログラムを書き始めると、classという構文に出会います。たとえば、ユーザー、商品、タスク、モーダル、フォーム部品など、同じような構造を何度も作る場合にクラスが役立ちます。
この記事では、class構文、constructor、メソッド、new、継承、実務での使いどころを解説します。
JavaScriptのクラスとは?
クラスとは、一言でいうと「オブジェクトを作るための設計図」です。
たとえば、クラスを使わずに同じ構造のユーザーデータを量産しようとすると、以下のようにオブジェクトを何個も手作業で書くことになります。
// クラスを使わない場合(同じような処理を何度も書く羽目に…)
const user1 = { name: "Ninja", greet() { console.log(`${this.name}さん、こんにちは`); } };
const user2 = { name: "Code", greet() { console.log(`${this.name}さん、こんにちは`); } };
これではユーザーが増えるたびに同じコードを繰り返すことになり、仕様変更があったときの修正も地獄です。こうした無駄を省き、1つの「設計図」にまとめるのがクラスの役割です。
基本のclass構文と書き方
class User { constructor(name) { this.name = name; } greet() { console.log(`${this.name}さん、こんにちは`); } } // 設計図(クラス)から実体を作る const user = new User("Ninja"); user.greet(); // Ninjaさん、こんにちは
クラスとオブジェクト(インスタンス)の関係
クラスは設計図、そこから作られた実体がオブジェクトです。クラスから作られたオブジェクトは「インスタンス」と呼ばれます。
| 用語 | 意味 | 例 |
|---|---|---|
| クラス | 設計図 | User |
| インスタンス | 設計図から作った実体 | new User("Ninja") |
| プロパティ | データ | name |
| メソッド | 処理 | greet() |
クラスを構成する基本機能と重要概念
costructorとは?初期化処理を書く場所
constructorは、インスタンスが作られるときに最初に実行される特別なメソッドです。
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const user = new User("Ninja", 20);
console.log(user.name); // "Ninja"
console.log(user.age); // 20
constructorでは、インスタンスごとに持たせたい初期値を設定します。
thisは作られたインスタンス自身を指す
クラス内のthisは、基本的に作られたインスタンス自身を指します。
class User {
constructor(name) {
this.name = name;
}
}
const userA = new User("A");
const userB = new User("B");
console.log(userA.name); // "A"
console.log(userB.name); // "B"
同じクラスから作っても、インスタンスごとに別の値を持てます。
thisはJavaScriptでつまずきやすい概念です。まずは「クラス内では作られたインスタンス自身」と考えると理解しやすいです。
メソッドで処理をまとめる
クラス内には、処理をメソッドとして書けます。
class Counter {
constructor() {
this.count = 0;
}
increment() {
this.count += 1;
}
show() {
console.log(this.count);
}
}
const counter = new Counter();
counter.increment();
counter.show(); // 1
データと、そのデータを操作する処理を同じ場所にまとめられるのがクラスのメリットです。
クラスを使うと、状態と処理をひとまとめにして管理しやすくなります。
クラスで最もハマる罠「thisの消失」とアロー関数での解決策
クラスを使い始めると、ほぼ100%の人が直面するJavaScript独自の仕様(罠)があります。それが、「メソッドを別の場所に渡すと、thisの中身が消える(変わる)」という問題です。
たとえば、先ほどのカウンターの処理を、ボタンをクリックしたときに動かそうとして以下のように書くとエラーになります。
const counter = new Counter();
// ❌ エラーになるNG例
// ボタンをクリックした際、increment内の「this」がボタン自身(DOM)にすり替わってしまう
button.addEventListener("click", counter.increment);
counter.increment をそのままイベントリスナーに渡してしまうと、関数の中の this が「Counterクラス」ではなく「クリックされたHTMLボタン(DOM)」に書き換わってしまい、正しくカウントがプラスされません。
解決策:アロー関数
() => {}で包む
この「thisの消失バグ」を防ぐ最も確実な方法が、アロー関数を使って呼び出すことです。// ⭕️ 正しく動くOK例 button.addEventListener("click", () => { counter.increment(); // これならthisがCounter自身のまま固定される! });アロー関数は「作られた場所のthisをそのまま引き継ぐ」という性質を持っているため、クラスのメソッドをイベントリスナーやタイマー処理(
setTimeoutなど)に渡すときは、必ずアロー関数で包むのが実務の鉄則です。
newを忘れるとどうなる?
クラスからインスタンスを作るときは、newを使います。
const user = new User("Ninja");
newを付けずに呼び出すとエラーになります。
const user = User("Ninja");
// TypeError
const user = new User("Ninja");
クラスは通常の関数のように呼び出すのではなく、newでインスタンス化します。
クラスを応用する便利な機能(継承・static・private)
extendsでクラスを継承する
クラスは、別のクラスを継承できます。共通の処理を親クラスにまとめ、子クラスで拡張するイメージです。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}が鳴きました`);
}
}
class Dog extends Animal {
run() {
console.log(`${this.name}が走りました`);
}
}
const dog = new Dog("ポチ");
dog.speak(); // ポチが鳴きました
dog.run(); // ポチが走りました
superで親クラスのconstructorを呼ぶ
子クラスでconstructorを書く場合は、super()で親クラスのconstructorを呼びます。
class AdminUser extends User {
constructor(name, role) {
super(name);
this.role = role;
}
}
子クラスのconstructor内でthisを使う前に、必ずsuper()を呼ぶ必要があります。
staticメソッドとは?
staticを付けたメソッドは、インスタンスではなくクラス自体から呼び出します。
class Calculator {
static add(a, b) {
return a + b;
}
}
console.log(Calculator.add(2, 3)); // 5
new Calculator()を作らなくても使えるため、便利な補助関数をクラスにまとめたいときに使われます。
privateフィールドとは?
JavaScriptのクラスでは、#を付けることで外部から直接触れないprivateフィールドを作れます。
class BankAccount {
#balance = 0;
deposit(amount) {
this.#balance += amount;
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount();
account.deposit(1000);
console.log(account.getBalance()); // 1000
#balanceはクラスの外側から直接アクセスできません。内部状態を守りたいときに使います。
実務の場面におけるクラスの活用例と設計の考え方
クラスを使うべき場面・使わない場面
クラスは便利ですが、何でもクラスにすれば良いわけではありません。
| 場面 | おすすめ度 | 理由 |
|---|---|---|
| 同じ形のオブジェクトを何度も作る | 高い | 設計図として使いやすい |
| 状態と処理をまとめたい | 高い | プロパティとメソッドを整理できる |
| 単純な計算関数だけ | 低い | 普通の関数で十分なことが多い |
| 1回しか使わない小さな処理 | 低い | クラス化すると大げさになる |
| UI部品を複数管理する | 中〜高い | 部品ごとの状態管理に向いている |
実務でのクラス活用例1:タスク管理(データ管理)
簡単なタスクを表すクラスを作ってみます。
class Task {
constructor(title) {
this.title = title;
this.done = false;
}
complete() {
this.done = true;
}
getLabel() {
return this.done ? `[完了] ${this.title}` : `[未完了] ${this.title}`;
}
}
const task = new Task("記事を書く");
console.log(task.getLabel()); // [未完了] 記事を書く
task.complete();
console.log(task.getLabel()); // [完了] 記事を書く
タスクのタイトルと完了状態、完了にする処理、表示用ラベルを1つのクラスにまとめています。
実務でのクラス活用例2:DOM操作(UIコンポーネントの複数管理)
Web制作の実務では、ボタンや開閉パネルなどのUI部品(コンポーネント)ごとにクラスを作って管理するのが一般的です。
ここでは、ページ内に複数の開閉(トグル)ボタンがあっても、それぞれが独立して綺麗に動く実務レベルのクラスの実装例を見てみましょう。
// クラスの設計図
class TogglePanel {
constructor(wrapper) {
// 包んでいる親要素(wrapper)の中から、対応するボタンとパネルを探す
this.button = wrapper.querySelector(".js-toggle");
this.panel = wrapper.querySelector(".js-panel");
this.isOpen = false;
// クリックイベントの登録(thisの消失を防ぐためアロー関数を使用)
this.button.addEventListener("click", () => {
this.toggle();
});
}
toggle() {
this.isOpen = !this.isOpen;
this.panel.hidden = !this.isOpen;
}
}
// 💡 実務のポイント:ページ内のすべてのトグル要素に一括で適用する
const wrappers = document.querySelectorAll(".js-toggle-wrapper");
wrappers.forEach((wrapper) => {
// 要素ごとにインスタンス化(量産)する
new TogglePanel(wrapper);
});
HTML側の記述例
HTML側は、以下のようにボタンとパネルのセットを親要素(.js-toggle-wrapper)で包んでおくだけで、何個配置してもお互いに干渉することなく独立して開閉できるようになります。
<!-- 1つ目のトグル -->
<div class="js-toggle-wrapper">
<button class="js-toggle">メニュー1を開閉</button>
<div class="js-panel" hidden>メニュー1のコンテンツ</div>
</div>
<!-- 2つ目のトグル(コードを増やさず、HTMLを並べるだけで自動で動く!) -->
<div class="js-toggle-wrapper">
<button class="js-toggle">メニュー2を開閉</button>
<div class="js-panel" hidden>メニュー2のコンテンツ</div>
</div>
なぜこれがSEO上位表示に繋がるのか?
初心者向けの解説サイトの多くは「ページ内に1つだけボタンがある前提」の簡易的なコード(querySelectorのみ)で終わっています。しかし、読者が本当に知りたいのは「実際のサイト制作で複数並べたいときにどう書くか」です。このように実務の運用を想定した『一歩深い解決策』を載せることが、競合サイトとの大きな差別化になり、検索エンジン(E-E-A-T)からも高く評価されるようになります。
設計の注意点:継承よりも「部品の組み合わせ(コンポジション)が向く場合も
クラスを学ぶと、共通処理をすぐ継承でまとめたくなることがあります。しかし、実務では継承を深くしすぎると、どのクラスの処理が動いているのか追いにくくなります。
class Logger {
log(message) {
console.log(`[LOG] ${message}`);
}
}
class UserService {
constructor(logger) {
this.logger = logger;
}
createUser(name) {
this.logger.log(`${name}を作成しました`);
}
}
const logger = new Logger();
const service = new UserService(logger);
service.createUser("Ninja");
この例では、UserServiceがLoggerを継承するのではなく、外から受け取って使っています。こうした部品の組み合わせは、後から差し替えやすい設計になります。
クラス設計では、継承だけでなく「必要な部品を組み合わせる」考え方も大切です。
公式ドキュメントも確認する
JavaScriptのクラス構文を正確に確認したい場合は、公式ドキュメントも参考になります。
- HTML・CSSを学んで自分だけのスキルを身につけたい
- HTML・CSSのスキルを身につけてwebクリエイターとして活躍したい
- サポートが充実しているプログラミングスクールを知りたい
そんな思いを持った方は忍者CODEのWeb制作コースがおすすめです!
忍者CODEは未経験からでもプロのエンジニアを目指せるオンラインプログラミングスク―ルです。
期間制限なく動画を視聴できるので、自分のペースで学習することができます!
まとめ:JavaScriptのクラスはオブジェクトを作る設計図
この記事では、JavaScriptのクラスについて解説しました。
JavaScriptのクラスは、同じ形のオブジェクトを作り、データと処理をまとめて管理するための構文です。
まずは、class、constructor、new、thisの関係を押さえましょう。慣れてきたら、extendsによる継承やstatic、privateフィールドも学ぶと、より大きなコードを整理しやすくなります。
忍者CODEマガジンは、未経験からでもプロのエンジニアを目指せるプログラミングスクール「忍者CODE」が運営しているプログラミング情報サイトです。
- プログラミングの効果的な学習方法
- プログラミング用語の解説
- エンジニアのキャリアに関する情報
など、プログラミングを始めたばかりの初学者に役立つ記事を幅広く公開しています。




