====== JavaScript オブジェク指向構文 ======
--- //[[http://www.y2sunlight.com/water|y2sunlight]] 2021-05-31//
本章では、ES2015[[js:top#ECMAScript|*2015]]で採用されたオブジェクト指向構文を中心にモダンなコードの記述方法について説明します。それ以前のオブジェクト指向を実装するための文法については、[[js:object:basic|オブジェクトの基本]]を参照して下さい。
===== class構文 =====
ES2015[[js:top#ECMAScript|*2015]]では、class構文が追加され、他のオブジェクト指向言語と同様に直感的なクラス定義ができるようになりました。
class Student {
// コンストラクタの定義
constructor(name) {
// プロパティの定義
this.name = name;
}
// メソッドの定義
greeting() {
console.log(`I am ${this.name}.`);
}
}
var suzuki = new Student('Suzuki');
suzuki.greeting(); // I am Suzuki.
class構文は内部的に新しく導入された構文ではなく、あくまでもこれはES2015[[js:top#ECMAScript|*2015]]以前のfunctionコンストラクタの[[https://ja.wikipedia.org/wiki/%E7%B3%96%E8%A1%A3%E6%A7%8B%E6%96%87#:~:text=%E7%B3%96%E8%A1%A3%E6%A7%8B%E6%96%87%EF%BC%88%E3%81%A8%E3%81%86%E3%81%84%E3%81%93%E3%81%86%E3%81%B6%E3%82%93,%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%82%E3%81%AE%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82|構文糖]]です。関数型のプロパティとして実装していたメソッドは、他の言語と同様に関数定義として記述できるようになりました。
但し、class構文には以下の制限があります。これらは制限というよりも、・・・です。
* new演算子無しで呼び出すことができない
* class構文の前にインスタンス化することができない
\\
===== アクセッサー =====
ES2015[[js:top#ECMAScript|*2015]]ではclass構文の中でアクセッサーを定義できるようになりました。
class Student {
// コンストラクタの定義
constructor(name) {
// プロパティの定義
this._name = name;
}
// ゲッター
get name() {
return this._name;
}
// セッター
set name(value) {
this._name = value;
}
// メソッドの定義
greeting() {
console.log(`I am ${this._name}.`);
}
}
var suzuki = new Student();
suzuki.name = "Suzuki";
console.log(suzuki.name); // Suzuki
suzuki.greeting(); // I am Suzuki.
\\
===== 静的プロパティと静的メソッド =====
''static'' キーワードをメソッドの先頭に付与することで、静的メソッドを定義することが出来ます。
class Student {
// コンストラクタの定義
constructor(name) {
// プロパティの定義
this.name = name;
}
// メソッドの定義
greeting() {
console.log(`I am ${this.name}.`);
}
// 静的プロパティの定義
static age = 15;
// 静的メソッドの定義
static getSchoolName() {
return 'AbcSchool';
}
}
console.log(Student.age); // OK (15)
console.log(Student.getSchoolName()); // OK (AbcSchool)
静的メソッドは、インスタンスからアクセスすることはできません。
var taro = new Student('taro');
taro.name = 'suzuki taro' // OK
taro.greeting(); // OK (I am suzuki taro.)
console.log(taro.age); // NG (undefined)
console.log(taro.getSchoolName()); // NG (taro.getSchoolName is not a function)
\\
===== 継承 =====
ES2015[[js:top#ECMAScript|*2015]]以前の構文ではprototypeチェーンを使って継承していましたが、新しい構文では ''extends'' と ''super'' キーワードを使いこれを実現することができます。
下の例は、前述のStudentクラスを継承した例です。
class Student {
constructor(name) {
this._name = name;
}
greeting() {
console.log(`I am ${this._name}.`);
}
}
class SchoolStudent extends Student {
constructor(name, school) {
super(name);
this.school = school;
}
greeting() {
console.log(
`I am ${this._name} attending ${this.school}.`
);
}
}
var taro = new SchoolStudent('Suzuki Taro', 'Sunlight Programming School');
taro.greeting(); // I am Suzuki Taro attending Sunlight Programming School.
\\
===== オブジェクト初期化子 =====
オブジェクト初期化子は中括弧 ( ''{}'' ) で囲まれたオブジェクトのプロパティのリストです。
=== プロパティと同名の変数で初期化する場合 ===
プロパティと同名の変数でオブジェクト初期化子で使用する場合は、より短く記述することができます。
var obj1 = {}; // var obj2 = new Object(); と同じ
var obj3 = {
name: 'Suzuki Taro',
school: 'Sunlight Programming School',
age: 15
};
=== プロパティの動的生成 ===
ES2015[[js:top#ECMAScript|*2015]]ではブラケット( ''[]'' )を使って動的にプロパティ名を生成することができます。この機能は、Computed Property Names と呼ばれています。
let prop = 'name';
let i = 0;
let taro = {
[prop]: 'Suzuki Taro',
['School' + (++i)]: 'Sunlight Programming School',
['School' + (++i)]: 'Hidaka Higashi Junior High School'
};
console.log(taro);
// {name: "Suzuki Taro", School1: "Sunlight Programming School", School2: "Hidaka Higashi Junior High School"}