PUROGU LADESU

ポエムがメインのブログです。

Javascriptの落とし穴5

クラス(プロトタイプ)

Javascriptではプロトタイプベースという方式でクラスを実現しています。
これが一番クセ者です。ES6ではclassキーワードが使えるようになり、多少マシになりましたが。

コンストラクタはただの関数リテラルです。コンストラクタ、メソッドにアロー関数は使えません。
newキーワードを忘れてはいけません。

var Member = function (firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.getName = function () {
    return `${this.firstName} ${this.lastName}`;
  };
};
var me = new Member("boris", "jonson");

生成されたインスタンスにあとからメソッド、メンバーを追加できる(Object.sealで凍結できる)
コンストラクタでも定義できるが、こちらのほうがメモリ効率的に有利。

Member.prototype.setName = function (firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
};
me.setName("aho", "sakata");

プロトタイプを使わずに追加すると静的プロパティ、メソッドになります。
静的プロパティ:読み取り専用が基本
静的メソッド:インスタンス変数、インスタンスメソッドにはアクセスできない

Member.version = 1.2;
Member.getVersion = function () {
  console.log(this.version);
};

継承はprototypeに追加します。

var ClassA = function () {
  ClassB.call(this); // コンストラクタを引き継ぐ
};
ClassA.prototype = new ClassB(); // ClassAでClassBを使う

クラス(ES6)

constructorでコンストラクタを定義します。
アクセス修飾子は使えいので、全てパブリック。(ES2022で、プライベート使用可能)
getter, setterはget setキーワードをつける。
静的プロパティ、メソッドはstaticをつける。

// プライベート変数はアンダースコアをつける。(可読性のため)
class Member {
  constructor(firstName, lastName) {
    this.firstName = firstName; // setterを呼んでる
    this._lastName = lastName; // 普通に代入

    // 上記はthisと変数をマージすれば簡単にプロパティにできる
    // Object.assign(this, { firstName, lastName });
  }

  // プロパティ
  get firstName() {
    return this._firstName;
  }

  set firstName(value) {
    this._firstName = value + "!";
  }

  getName() {
    return `${this.firstName} ${this.lastName}`;
  }

  // 静的プロパティ
  static version = 1.2;
  // 静的メソッド
  static getVer() {
    // thisで同じクラスの静的プロパティ、メソッドを呼び出す
    return this.version;
  }
}

let me = new Member("boris", "jonson");
me.firstName = "kim";
console.log(me.firstName);
console.log(Member.getVer());


ES2022で、#をつけるとプライベート変数、プライベートメソッドになる。
プライベート化するとクラス外からアクセスできない。
インスタンス変数の宣言はコンストラクタの中でなくてもできるようになった。

class Car {
  #name;
  constructor(name) {
    this.#name = name;
  }
  get name() {
    return this.#name;
  }

  set name(val) {
    this.#name = val;
  }
}

let car = new Car("vezel");
car.name = "yaris";
console.log(car.name);

継承はextendsを使う。

class ClassA extends ClassB {
  constructor() {
    super()
  }
}