クラスとインスタンス
このレッスンで分かること
classとconstructorで、同じ形のオブジェクトを何個でも作れます- メソッドの中の
thisは、呼び出したインスタンスを指します
データ専用の関数が、データから離れていく
入門では、プロフィールのスキルを素のオブジェクトの配列で持っていました。
JavaScript
const skills = [
{ name: "HTML", hours: 12 },
{ name: "CSS", hours: 8 }
];
function caption(skill) {
return skill.name + " " + skill.hours + " 時間";
}
function needsPractice(skill) {
return skill.hours < 10;
}caption も needsPractice も、スキルにしか使えない関数です。それなのにスキルのデータとは別の場所に置かれています。あとで hours を minutes に変えると、離れた場所にある関数を全部探して直すことになります。データと、そのデータ専用の処理が離れているのが原因です。
設計図を書いて、実体を作る
class を使うと、その 2 つを同じ波かっこの中に置けます。
JavaScript
class Skill {
constructor(name, hours) {
this.name = name;
this.hours = hours;
}
caption() {
return `${this.name} ${this.hours} 時間`;
}
needsPractice() {
return this.hours < 10;
}
}
const first = new Skill("HTML", 12);
console.log(first.caption()); // HTML 12 時間
console.log(first.needsPractice()); // falsenew Skill("HTML", 12) を書いたとき、JavaScript は次の順に動きます。
| 順番 | 起きること |
|---|---|
| 1 | 中身が空のオブジェクトが 1 個作られる |
| 2 | そのオブジェクトを this として constructor が呼ばれる |
| 3 | this.name = name などでプロパティが書き込まれる |
| 4 | できあがったオブジェクトが new 式の値として返る |
constructor の中では return を書きません。書かなくても、作られたオブジェクトが返ります。new を書き忘れて Skill("HTML", 12) と呼ぶと TypeError になります。クラスは new なしでは呼べない決まりなので、間違いに気付きやすい形です。
メソッドは、インスタンスを 100 個作っても 100 個には増えません。実体は 1 つで、全インスタンスがそれを見に行きます。this は「どのインスタンスから呼ばれたか」で決まるので、a.caption() なら this は a、b.caption() なら this は b です。
配列をまるごとインスタンスに変える
外から届くデータは素のオブジェクトです。第2章で使った map を通せば、配列ごと変えられます。
JavaScript
const records = [
{ name: "HTML", hours: 12 },
{ name: "CSS", hours: 8 }
];
const list = records.map((record) => new Skill(record.name, record.hours));
console.log(list.map((skill) => skill.caption()));
console.log(list.filter((skill) => skill.needsPractice()).length); // 1一度インスタンスにしてしまえば、そのあとは map も filter もこれまでどおりです。違うのは、配列の中身が処理のしかたを自分で知っている点です。
クラスは「オブジェクトの新しい書きかた」ではありません。同じ形のものが何個も出てきて、そのすべてに同じ処理をしたいときに効きます。1 個しか作らないなら、素のオブジェクトのままで十分です。
よくある間違い
- メソッドの間にカンマを書く — オブジェクトリテラルの感覚でカンマを打つと構文エラーです。クラスの本体はカンマで区切りません
- メソッドの中で
thisを書き忘れる —${name}とだけ書くと、インスタンスのプロパティではなく変数を探しに行き、見つからなければReferenceErrorです constructorで値を返そうとする — オブジェクトをreturnするとnewの結果がそれに差し替わり、メソッドを持たない素のオブジェクトができます。thisに代入するだけにします
要件
- constructor で title、year、views を同じ名前の this のプロパティに代入する
- label() で タイトル (年) の形の文字列を返す
- isPopular() で views が 100 以上なら true、それ以外なら false を返す
- buildWorkSummary(items) は変更しない。戻り値の labels と popularCount の集計は準備済み