trifle

技術メモ

ES6 のクラス 覚え書き

const, let やらアロー関数やらasync, await やらにはそこそこ慣れてきたが, クラスについては曖昧な理解のままな気がしたので,

を読んで部分的にまとめておく.



クラスを定義する

クラスの定義はクラス宣言(Class declarations)クラス式(Class expressions)(適切な訳なのか?)の2種類がある.

宣言

class Recktangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    calcArea() {
        return this.height * this.width;
    }
}

console.log(Recktangle.name); // Recktangle

const square = new Recktangle(100, 50);
console.log(square.calcArea()); // 5000


// 名前をつける
const namedRecktangle = class Recktangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    calcArea() {
        return this.height * this.width;
    }
}

console.log(namedRecktangle.name); // Recktangle

const named = new namedRecktangle(100, 50);
console.log(named.calcArea()); // 5000

// 名前をつけない
const unnamedRecktangle = class {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    calcArea() {
        return this.height * this.width;
    }
}

console.log(unnamedRecktangle.name); // unnamedRecktangle

const unnamed = new unnamedRecktangle(100, 50);
console.log(unnamed.calcArea()); // 5000

どれで書いても良い気がするのだが. const namedRecktangle = class Recktangle のように, 変数名としての名前とクラス名としての名前を変えられると, 名前の付け方で抽象度を変えたい時に気持ちがうれしいのかもしれない.
なお, 関数とは異なり, 「先に使って後で定義する」という巻き上げ(hoisting)ができない.


クラスの本体を定義する

コンストラクタとかメソッドはまあいいでしょう.
getter, setter を知らなかった. これはオブジェクトにもあるようだ(むしろオブジェクトで関数が使えるメリットの方が強い気がする).

九章第六回 ゲッタとセッタ — JavaScript初級者から中級者になろう — uhyohyo.net

↑これが分かりやすい.

class Human {
    constructor(age, years) {
        this.age = age;
        this.years = years;
    }

    nennrei() {
        return this.age + this.years;
    }

    get saba() {
        return this.nennrei() - 10;
    }
}

const Hanako = new Human(42, 6);
console.log(`${Hanako.years}年後には${Hanako.saba}歳です。本当は${Hanako.nennrei()}歳です。`)
// 6年後には38歳です。本当は48歳です。

あまり使い道が思いつかなかった. クラスならメソッドで済むのでそれで十分なような.


Static メソッド

普通のメソッドはクラスから生成される一つ一つのインスタンスの性質についてあれこれやるのに対して, static メソッドはクラス自体の性質についてあれこれやる. メタなメソッドである.

class Human {
    constructor(age) {
        this.age = age;
    }

    bornYear() {
        return 2018 - this.age;
    }

    static ageDiff(h1, h2) {
        return Math.abs(h1.age - h2.age);
    }
}

const Taro = new Human(20); 
const Hanako = new Human(24); 
console.log(Taro.bornYear()); // 1998
console.log(Hanako.bornYear()); // 1994
console.log(Human.ageDiff(Taro, Hanako)); // 4


クラスの継承

extends で継承.

class Japanese {
    constructor(firstname, lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }

    get name() {
        return `${this.firstname}${this.lastname}`
    }

    speak() {
        return `こんにちは。${this.name}です。`
    }
}

const Man1 = new Japanese("田中", "学");
console.log(Man1.speak()); // こんにちは。田中学です。

class American extends Japanese {
    get name() {
        return `${this.lastname} ${this.firstname}`
    }

    speak() {
        return `Hello! I'm ${this.name}.`
    }
}

const Man2 = new American("Twain", "Mark");
console.log(Man2.speak()); // Hello! I'm Mark Twain.

コンストラクタ自体を上書きする際はsuperを使うとよい. また, 継承元の関数を再利用したい際にも super が使える.

class Rectangle2D {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }

    getArea() {
        return this.a * this.b;
    }
}

class Rectangle3D extends Rectangle2D {
    constructor(a, b, c){
        super(a, b); // super の使い方その一
        this.c = c;
    }
    
    getVolume() {
        return this.a * this.b * this.c;
    }

    getOneSideArea() {
        return super.getArea(); // super の使い方その二
    }
}

const zukei1 = new Rectangle2D(3, 4);
const zukei2 = new Rectangle3D(3, 4, 5);
console.log(zukei1.getArea(3, 4)); // 12
console.log(zukei2.getVolume(3, 4, 5)); // 60
console.log(zukei2.getOneSideArea(3, 4, 5)); // 12


ミックスイン

複数のクラスから継承したい際に使う.