JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptクラス入門ガイド:定義から継承、ゲッター・セッターまで徹底解説

JavaScriptはプロトタイプベースの言語です。オブジェクトを宣言するたびに、そのオブジェクトに関連付けられたプロパティやメソッドを拡張するプロトタイプが自動的に生成されます。

近年、多くのJavaScript開発者がオブジェクト指向設計をコードに取り入れようと試みてきました。そこで登場したのが「クラス」と呼ばれる新しいオブジェクトの形です。クラスは、既存のプロトタイプを拡張する仕組みとして機能します。

このガイドでは、クラスとは何か、なぜ使われるのか、そして自分のコードにどう実装すればよいのかを解説します。実際のコード例も交えながら、クラスを使い始めるための一歩をサポートします。

JavaScriptクラスとは?

クラスとは、オブジェクトのテンプレート(雛形)を宣言するための仕組みです。

オブジェクト指向プログラミング言語に馴染みがある方なら、それらがクラスとオブジェクトに大きく依存していることをご存じでしょう。クラスは、ある種のデータの設計図のようなものです。どんなデータを格納でき、どのメソッドにアクセスできるかを定義します。そして、オブジェクトはそのクラスのインスタンス(実体)です。

例としてBookクラスを挙げてみましょう。このクラスには、書籍に関する情報として何を格納できるか、そのデータをどう操作できるかという設計図が含まれます。そして、「欲望という名の電車」という個別の書籍は、このクラスのオブジェクト(インスタンス)にあたります。

JavaScriptにおいて、クラスはいわゆる「糖衣構文(シンタックスシュガー)」です。クラス構文は便利で書きやすいのですが、必ずしも新しい機能を追加しているわけではありません。

クラスは、ReactやNext.jsといったモダンなJavaScriptフレームワークでも広く使われています。

クラスと関数の違い

この記事から一つだけ覚えて帰るなら、これです。クラスは普通の関数にすぎません

クラスと関数式の唯一の違いは宣言方法です。関数はfunctionキーワードを使い、クラスはclassキーワードを使います。技術的には、classキーワードを使わずにクラスを宣言することすら可能です。

両者が同じものであることは、関数とクラスを作成して、それぞれのプロトタイプを出力してみれば確認できます。

const PlayerFunction = function() {}
const PlayerClass = class {}

console.log(Object.getPrototypeOf(PlayerFunction));
console.log(Object.getPrototypeOf(PlayerClass));

実行結果は次のようになります。

function ()

function ()

関数でもクラスでも、同じプロトタイプベースのアーキテクチャが使われていることが分かります。

クラスの定義方法

では、クラスはどうやって定義するのでしょうか。

クラスはclassキーワードを使って定義できます。クラスを定義したら、constructor()関数を使ってデフォルト値で初期化できます。

JavaScriptコンソールを開いて、次のコードを貼り付けてみましょう。

class Book {
	constructor(title, author) {
		this.title = title;
		this.author = author;
	}
}

これでBookというクラスが作成されました。このクラスは、コンストラクターメソッドで定義したtitleとauthorの2つの値を保持できます。このクラスのオブジェクトを作成するには、次のコードを使います。

var streetcar = new Book("A Streetcar Named Desire", "Tennessee Williams");

クラスから値を取得する方法は、通常のオブジェクトとまったく同じです。

console.log(streetcar.title);

実行結果:A Streetcar Named Desire

クラスメソッドの定義方法

プロトタイプではなくクラスを使うメリットの一つは、クラスの中に直接メソッドを宣言できることです。つまり、既存の関数に新しいメソッドを追加するためにprototype構文を使う必要がありません。

次の例を見てみましょう。

class Book {
	constructor(title, author) {
		this.title = title;
		this.author = author;
	}
	
	getDetails() {
		console.log(`${this.title} is a book written by ${this.author}.`);
	}
}

getDetails()というメソッドをクラス内に宣言しました。関連するコードがひとまとめになるため、コードの見通しが良くなるのが嬉しいポイントです。それでは、getDetails()関数を呼び出してみましょう。

var streetcar = new Book("A Streetcar Named Desire", "Tennessee Williams");
streetcar.getDetails();

実行結果:

A Streetcar Named Desire is a book written by Tennessee Williams.

クラスの継承

他のオブジェクト指向の仕組みと同様に、クラスは他のクラスからプロパティを継承できます。

継承とは、子クラスが親クラスのメソッドやデータにアクセスできるようにする仕組みです。クラスを継承するには、extendsキーワードを使用します。JavaScriptファイルを作成するか、コンソールを開いて次のコードを貼り付けてください。

class Fiction extends Book {
	constructor(title, author, fiction) {
		super(title, author);

		this.fiction = true;
	}
}

ここでは、先ほど宣言したBookクラスを設計図として利用するFictionクラスを作成しました。コード内ではsuper()キーワードを使って、親クラスであるBookからtitleとauthorの値を継承しています。さらに、新しい属性fictionを定義し、デフォルト値をtrueに設定しました。

新しいFictionクラスのオブジェクトを作成してみましょう。

var gatsby = new Fiction("The Great Gatsby", "F. Scott Fitzgerald");
console.log(gatsby.fiction);

実行結果:true

Fictionクラスにはfictionという項目が保存され、デフォルトでtrueになっています。もしBookクラスのインスタンスからこの値にアクセスしようとしても、何も返されません。「fiction」はFictionクラスでのみアクセスできるからです。

ゲッターとセッター

クラスを扱う際には、ゲッター関数とセッター関数を活用しましょう。

ゲッター関数はクラスから値を取得するために使い、セッター関数はクラス内の特定の値を変更するために使います。これらの関数は、それぞれgetキーワードとsetキーワードで表します。

次のコードを見てください。

class Book {
	constructor(title, author) {
		this.title = title;
		this.author = author;
	}
	
	get author() {
		return this.author;
	}

	set author(author) {
		this.author = author;
	}
}

この例では、authorという名前の2つのメソッドを宣言しています。一方はauthorの値を取得するためのゲッター(get)メソッド、もう一方はauthorの値を変更するためのセッター(set)メソッドです。

補足:上記のコードをそのまま実行すると、get author()内でthis.author自身を参照してしまうため、無限再帰によるエラー(Maximum call stack size exceeded)が発生します。実務では、_authorのような別名の内部プロパティを持たせ、ゲッター・セッターからはそちらを参照するのが一般的です。

ゲッターとセッターの動作イメージは、次のコードで確認できます。

var streetcar = new Book("A Streetcar Named Desire", "");
streetcar.author = "Tennessee Williams";
console.log(streetcar.author);

実行結果:Tennessee Williams

まず、streetcarというオブジェクトを初期化し、タイトルにA Streetcar Named Desireを設定しました。次に、コード内で定義したセッターを使ってauthorの値をTennessee Williamsに変更します。最後に、ゲッターメソッドを使ってauthorの値をコンソールに出力しました。

まとめ

クラスはJavaScriptに新しい機能を追加するわけではありませんが、オブジェクト指向プログラミングに慣れている開発者にとっては、関数をより理解しやすい形で書くための強力な手段となります。

クラスはJavaScriptのプロトタイプベースの設計を抽象化し、コードをよりオブジェクト指向らしく見せてくれます。「見せてくれる」という点が重要です。思い出してください。クラスは関数であり、その実体は糖衣構文にすぎません。

これであなたも、JavaScriptのエキスパートのようにクラスを使いこなす準備が整いました!

  1. JavaScriptのappendChild()メソッド徹底解説!基本的な使い方と実践例

    JavaScriptのappendChild()メソッドは、親ノードの末尾に新しい要素を追加するためのメソッドです。特に、<ul>や<ol>などのリストに<li>項目を動的に追加する場面でよく使われます。複数の項目を追加したい場合は、appendChild()を必要な回数だけ呼び出すことになります。 JavaScriptのappendChild()とは? Webページにはテキストのリスト、画像のリスト、カスタム要素のリストなど、さまざまなリストがあふれています。通常、リストを作成するときはHTMLで直接記述しますが、appendChild()メソッドを使

  2. JavaScriptのclassキーワードとは?クラス定義の基本をわかりやすく解説

    ES6(ECMAScript 2015)で導入されたJavaScriptのクラスは、プロトタイプベースの継承に対する「構文糖衣(シンタックスシュガー)」と呼ばれています。実体は「特別な関数」であり、classキーワードを使うことで、より直感的で読みやすいコードとしてオブジェクト指向プログラミングを実現できます。 classキーワードによる基本的なクラス定義 classキーワードを使用したクラス定義の基本構文は以下の通りです。 class Person { // このクラスのコンストラクタ constructor(name) { this.name = name;