JavaScriptクラスの基礎: ES6とES7のクラス構文の使い方と仕組みを解説
本日のチュートリアルはJavaScriptのクラスについて学習します。
JavaScriptクラスを学習し始めたあなたは中級者レベルに到達しています。
Reactなどの一般的なJavaScriptライブラリはクラス構文を頻繁に使用するため、クラスに精通していると非常に役立ちます。
本日はES6クラス構文およびES7クラス構文の解説を致します。
JavaScriptにおけるクラスとPrototypeの違いは、他の記事として取り扱いますが、Prototypeについて精通していない初心者様もいらっしゃるかと思いますので短めに解説します。
この記事では、すでに(Prototype)および(this)にある程度精通している方を対象としている事をご理解ください。
Prototypeとは?
JavaScriptにおけるprototypeは、あるオブジェクトのプロパティやメソッドを他のオブジェクトから継承するための仕組みです。
すべてのJavaScriptのオブジェクトは、 prototypeという特別なプロパティを持っています。
このprototypeは、オブジェクトの「元」となる別のオブジェクトを指します。
この「元」となるオブジェクトには、プロパティやメソッドが定義されていることがあります。
例えば、下記のコードをご確認下さい。
Person
オブジェクトのprototypeにsayHello
メソッドが定義されます。
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.sayHello = function() { console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`); }; const taro = new Person("Taro", 30); taro.sayHello(); // "Hello, my name is Taro and I'm 30 years old."
Person
コンストラクター関数のprototypeに sayHello
メソッドが定義されることで、taro
オブジェクトが sayHello
メソッドを継承することができます。
つまり、 taro.sayHello()
というコードを実行すると、 Person
のprototype に定義されたsayHello
メソッドが呼び出されます。
prototypeは、オブジェクトのプロパティやメソッドを継承するための一般的な方法であり、JavaScriptでのオブジェクト指向プログラミングにおいて重要な概念となっております。
クラスとは?
JavaScriptクラスはECMAScript2015(ES6)で導入されました。
ES6以前では、クラスの概念がなかったので関数を使用しプロトタイプの方法で実装していました。
クラスは、他のプログラミング言語とは異なり、JavaScriptのシンタックスシュガーです。
JavaScriptには適切なクラスが含まれていません。
クラスは、関数でのプロトタイプを使用した以前でのメソッドを置き換え、オブジェクトテンプレートを作成するために改善され、よりクリーンな構文を提供するためのJavaScriptのクラス概念となっております。
つまり、JavaScriptのクラスはオブジェクトではなく、JavaScriptオブジェクトを作成するためのテンプレートのようなものです。
JavaScriptにおけるクラスは、オブジェクト指向プログラミングにおける重要な概念の一つです。
それでは、JavaScriptクラスの基本的な使用方法を説明します。
JavaScriptクラス構文
クラスは特殊な種類の関数なので、関数宣言や関数式(無名関数)と同じようにクラスを定義できます。
クラスは関数に似ています。
・ クラス関数宣言(名前付き)
・ クラス関数式(無名関数)
これらはclassキーワードによって宣言されます。
JavaScriptは、クラスを定義する主要な方法であるclassキーワードを提供します。
これは、既存のプロトタイプ継承パターンに対するシンタックスシュガーとして機能します。
JavaScriptクラスを作成するには、classキーワードの後にクラスの名前を続けます。
以下のClassname
はクラスの名前です、クラス名は通常ではクラス名の先頭に大文字を使用して定義されます。
// クラス宣言 class Classname { { class 本体 } }
以下でのnewはクラスをインスタンス化します。
新しい空のオブジェクトが作成され、thisに割り当てられます。
const Classname = new Classname();
Classname
クラスの新しいオブジェクトであるインスタンスを作成する方法です。
console.log(typeof Classname); // function
インスタンスに関しましては、後に詳しく解説致します。
JavaScriptでは、クラスは一種の関数となっています。
かならずしもクラスに名前を付ける必要はありません。
クラス式を使用すると、クラスを変数に割り当てることができます。
以下では、無名関数である名前無しの宣言となります。
const User = class {} // unnamed const User = class User {} // named
これらのように、クラスは名前付きまたは名前なしにすることができます。
名前付きクラス式に付けられた名前は、クラスの本体に対してローカルです。
名前付きクラスと無名クラスの最も重要な違いは、名前付きクラスが再利用可能であることです。
名前付きクラスは、複数の場所で同じ名前で参照できます。
一方で、無名クラスは、そのインスタンスを作成するためにのみ使用され、再利用することはできません。
初期化
クラスは関数の一種であり似ておりますが、実際には関数とは多少異なる部分があります、それはJSのクラスは巻き上げられません。
JavaScriptのクラスには、constructorと呼ばれる特別なメソッドがあり、オブジェクトの初期化時にフィールドの初期値を設定できます。
つまり、constructorはオブジェクトの作成とプロパティを初期化するために使用される関数オブジェクトです。
指定されたクラスの新しいオブジェクトが作成されると、自動的に実行されます、 constructor関数は、関数自体を参照しthis
のプロパティとして割り当てられ、いくつかのパラメーターで初期化されます。
class User { constructor(name, age){ this.name = name this.age = age } }
引数は括弧()で囲まれ、その後に中括弧{}で囲まれたコードブロックが続きます。
これらの中括弧は、メソッド本体の開始位置の開き中括弧{と終了位置の閉じ中括弧}を示します。
外側にあるペアの中括弧は、クラス自体そのものを定義し、内側のペアの中括弧はconstructorメソッドの境界を定義するために使用されています。
thisキーワードを使用して現在のクラスを参照します。
また、constructorメソッドは1つしか存在できません。
thisキーワードに精通されていない方は、当ブログの以下のチュートリアルを参照してみて下さい。
クラスのインスタンス化
インスタンスとは、クラスのプロパティ名とメソッドを含むが、一意のプロパティ値を持つオブジェクトです。
つまり、インスタンスはクラスによって記述されたデータと動作を含むオブジェクトという事です。
例えば、クラスはカテゴリと考えることもできます。
各クラスは異なる値を含み、クラスのインスタンス(オブジェクト)の状態を記述する属性
やプロパティ
を持つことができます。
各ユーザー情報の異なる値と考えてみて下さい。
クラスのインスタンスを作成するとは、それらをクラスとして管理するのがインスタンスになります。
クラスを使ってオブジェクトを作成するには、newキーワードを使用します。
class User { constructor(name, age){ this.name = name this.age = age } } const user = new User('Taro', 30); document.write("出力:" + " " + user.name + " " + user.age);
上記のコードでは、newキーワードを使用してUser
クラスからuser
というインスタンスを作成しています。
this.name = name
という式で、フィールドのname
を作成し、初期値を代入しています。
User
クラスのconstructorメソッドが呼び出され、name
プロパティに"Taro"
、age
プロパティに30
が設定されます。
これで、新しいuser
オブジェクトを作成し、そのname
プロパティにアクセスできるようになりました。
See the Pen JavaScript クラス定義 初期化 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
クラスのメソッド
クラスは、メソッドを追加するためのよりクリーンで洗練された構文を提供しています。
class User { constructor(name) { this.name = name; } getName() { return this.name; } }
this
キーワードを使用すると、constructorとメソッド内のインスタンスデータにアクセスできます。
const user = new User('Taro'); console.log(user.getName()); // Taro
メソッド呼び出しのuser.getName()
は、Userクラス内のメソッドを実行し、name
プロパティを返します。
See the Pen JavaScript クラス メソッド by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
他の例で、もう少し学んでみましょう。
class Person { constructor(name, age) { this.name = name; this.age = age; } sayHello() { console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`); } }
上記のコードでは、Person
というクラスを定義しております。
constructorメソッドは、クラスのインスタンスが作成されたときに呼び出される特別なメソッドで、name
とage
という2つの引数を受け取って、それぞれthis.name
とthis.age
というプロパティに値を設定しています。
sayHello
メソッドは、this.name
とthis.age
の値を使って、挨拶をするためのメソッドとなります。
静的メソッド
メソッドをそのプロトタイプではなく、クラス関数自体に割り当てることも可能です。
そのようなメソッドはstatic(静的)と呼ばれ、以下のキーワードが先頭に追加されます。
class Double { static double(n) { return n * 2; } } Double.double(2); // 4
上記のDoubleクラスのdoubleメソッドは、与えられた数値を2倍にする単純な計算を行っています。
静的メソッドでは、クラスのインスタンス特有のデータや状態にアクセスすることはできませんが、その代わりに引数を受け取って処理を行います。
このような簡単な計算や処理を行う場合、インスタンスを作成する必要はなく、クラス自体で直接メソッドを呼び出すことができるため、静的メソッドが有用です。
このように、静的メソッドはユーティリティクラスで計算を行うためによく使用されます。
クラスの拡張および継承
extends
キーワードを使用して、JavaScriptのオブジェクトとクラスを拡張できます。
※ 一部のクラスを拡張するクラスは子クラスと呼ばれ、他のクラスは親クラスと呼ばれます。
通常では、別のクラスの子であるクラスを作成するために使用されます。
クラスを拡張する理由は、新しいクラスに元のクラスと同じ機能をすべて持たせたい場合は、クラスを拡張します。
子クラスは、新しい機能を追加するか、親クラスのいくつかの機能をオーバーライドすることができます。
つまり、extendsキーワードは、他のクラスまたは親クラスに存在するプロパティとメソッドにアクセスするのに役立ちます。
ES6でクラスを拡張するプロセスは簡単です。
クラス名の後にextendsキーワードを記述し、拡張するクラスの名前を記述するだけです。
class ChildClass extends ParentClass{ // 定義 }
例えば、以下のようなクラスPerson
があるとします。
class Person { personInfo() { //... } }
このクラスを拡張し形成し、ベースクラスから拡張してpersonInfo()
メソッドを継承し、特定のメソッドやプロパティを提供できます。
class Student extends Person { studentInfo() { //... } }
ES6ではextendsとsuperキーワードを使用することで、以前のプロトタイプの継承手法の手順を簡略化しました。
以下の例では、Person
クラスとStudent
クラスを定義し、extendsとsuperキーワードで継承を確立しています。
class Person { constructor(name) { this.name = name; } personInfo() { console.log("生徒の名前: " + this.name); } } class Student extends Person { constructor(name) { super(name); } studentInfo() { console.log("親クラスの生徒の名前: " + this.name); } } let student = new Student("Taro"); student.personInfo(); student.studentInfo();
See the Pen JavaScript クラス 拡張 by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
まず、extendsキーワードを使用し、Person
クラスを継承したStudent
クラスにします。
//親クラス class Person { // ... } //子クラス class Student extends Person { // ... }
先述したように、上記であればPerson
クラスは基本クラスおよび親クラス呼ばれ、Student
クラスは派生クラスまたは子クラスと呼ばれています。
Student
クラスは、Person
クラスのすべてのプロパティとメソッドを継承します。
そして、Student
クラスのconstructorでsuper()を呼び出しname
を引数としてPerson
のconstructorを呼び出します。
class Student extends Person { constructor(name) { super(name); } }
JavaScriptでは、子クラスがconstructorを持つ場合はsuper()を呼び出すことが要求されます。
super
は親クラスからクラスを拡張する場合、子クラスを使用する前に親クラスを呼び出す必要があります。
JavaScriptによって提供されるsuper()メソッドがあるので、それが呼び出しを行います。
クラスにconstructorがない場合には、他に何もする必要はありません。
super()はthisオブジェクトを初期化するため、thisオブジェクトにアクセスする前にsuper()を呼び出す必要があります。
したがって、super()を呼び出す前にthisにアクセスしようとすると、エラーになりますので注意して下さい。
ES7 クラス構文
ECMAScript 7(2016)クラス構文の最も良い点は、constructorまたはsuper()メソッドを記述する必要がないことです。
それは、アロー関数をクラスメソッドとして使用することもできます。
これにより、コードの記述がより簡単かつ迅速になります。
class Person { firstName = "Taro"; personInfo = () => { console.log(`My name is ${this.firstName}`); document.write(`My name is ${this.firstName}`); }; } const person = new Person(); person.personInfo();
ES7クラス構文では、constructorとsuper()メソッドは裏側で書かれているので、あなたが書く必要はありません。
class Person { firstName = "Taro"; personInfo = () => { console.log(`My name is ${this.firstName}`); document.write(`My name is ${this.firstName}`); }; } class Student extends Person { firstName = "Taro"; lastName = "Tanaka"; printList = () => { `My name is ${this.firstName} ${this.lastName} `; }; } const personList = new Student(); console.log(personList); console.log(personList.printList());
See the Pen JavaScript ES7 クラス by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
最後に
同じ種類のオブジェクトを複数作成する必要がある場合は、クラスを使用します。
クラスは、 strict mode(厳格モード)で実行され、巻き上げられない特別な種類の関数となります。
クラスには、クラスインスタンスからアクセスできるフィールドとメソッドを含めることができ、それらを拡張することにより、他のクラスから機能を継承できます。
子クラスは親クラスのすべての機能を継承できるため、コードの再利用が可能になります。
それにより、コードがよりクリーンになり、保守が容易になります。
それだけでなく、子クラスに独自の機能を追加することもできるため、有用な機能だけを継承し、その他の必要な機能を定義することができます。
継承は、オブジェクト指向プログラミングの中心的な概念の1つであり、継承とは親クラスや基本クラスのメソッドや属性を子クラスや派生クラスにコピーまたは継承することであり、JavaScriptではextends
というキーワードを使って実現することができます。
プロトタイプの継承は時代遅れで複雑です。
extendsはより単純で、Java
、C++
などの他の言語に似ています。
本日は以上となります。
最後までこの記事を読んで頂きありがとうございます。