ユーザ用ツール

サイト用ツール


ecmascript:class

文書の過去の版を表示しています。


<markdown> # class

## クラス構文

```javascript class Test {

// 静的フィールド
static version = '1.0.0';

// 静的メソッド
static info() {
  // 注意 staticコンテキストでのthis.nameはクラス名を指す(`#name`ではない)
  return `${this,name} class, version ${this.version}`
}

// privateフィールド
#name = '';

// コンストラクタ
constructor(v) {
  this.#name = v;
}
// メソッド
getMessage() {
  return 'Hello from ${this.#name}'
}

// getter
get name() {
  return this.#name;
}

// setter
set name(v) {
  this.#name = v;
} 

} ```

## 継承

```javascript class Test2 extends Test {

// 拡張メソッド
print() {
  console.log(this.getMessage());
}

} ```

## 関数とnew

ここからはマニア向けのディープな話になる。JSの関数はコンストラクタとして機能し、new演算子によって新しいオブジェクトを生成できる

```javascript function Fuga(x) {

this.x = x;

}

const fuga = new Fuga(1);

console.log(typeof Fuga); // ⇒ function

// 普通の関数としても呼べる Fuga(); ```

以下のコードは実は上記のコードとほぼ同等。class構文で定義したクラスは実は関数なのである。このような関数はコンストラクタ関数と呼ばれる

```javascript class Fuga {

constructor(x) {
  this.x = x;	
}

} const fuga = new Fuga(1);

console.log(typeof Fuga); // ⇒ function

// ただしclassで定義した関数は直接呼べないように制限がかかっている Fuga(); // TypeError: Class constructor Fuga cannot be invoked without 'new' ```

※ ただしfunctionによるコンストラクタ定義は過去のコードとの互換性のために残されているので現在は非推奨でありclassキーワードを使うべき

これは何を意味しているかというとclassと銘打っているが、その実体はクラスではないということだ。クラスのような振る舞いはprototype chainという仕組みで行われている。

## constructorプロパティ

生成されたオブジェクトはconstructorというプロパティを持っている。これは自身を生成したコンストラクタ関数への参照である。

```javascript class Hoge {

constructor(name) {
  this.name = name;
}

getName() {
  return this.name;
}

}

const h = new Hoge(1)

console.log(h,constructor === Hoge); // ⇒ true

const h2 = new h.constructor(2); // newすることもできる ```

## prototypeプロパティ

コンストラクタ関数はprototypeというプロパティを持っている

```javascript console.log(Hoge.prototype); ```

classで定義したメソッドは、このprototypeプロパティが持っている。

```javascript console.log(Hoge.prototype,getName); // ⇒ [function getName]

console.log(Hoge.prototype,getName.call({ name: “にゃん” })); // ⇒ にゃん ```

コンストラクタ関数を通して生成されたオブジェクトは`proto`というプロパティを持っており、コンストラクタ関数のprototypeにアクセスできる

```javascript console.log(h.proto.getName); // ⇒ [function getName] ```

`h.proto`も`proto`を持っている。このようなprototypeの連鎖をprototype chainと呼ぶ

```javascript console.log(h.proto); // ⇒ {} console.log(h.proto.proto); // ⇒ [Object: null prototype] {} ``` 

何も継承していないクラスの場合prototype chainは2つで終わりだが、継承すると継承した回数だけprototype chainは長くなる。

prototype chainはメソッドの呼び出しに関係している。例えば`x.m()`というコードを実行すると次のようにメソッドが検索される

1. `x`自身プロパティ一覧からmという名前のプロパティを探し、見つかったらメソッドとして実行する。なければ2へ 2. `x,proto`のプロパティ一覧からmという名前の・・・、なければ3へ 3. `x.proto.proto`のプロパティ一覧からmという名前の・・・、なければ4へ 4. prototype chainの末端まで到達しても見つからない場合はTypeErrorとなる

### prototypeを指定してオブジェクトを生成

`Object.create`を使うと任意のオブジェクトをprototypeに設定して新しいオブジェクトを生成できる

```javascript const p = {

name: 'proto',
greet() {
  console.log("I am a " + this.name)
}

}

// pをプロトタイプに設定してオブジェクトを生成 const h = Object.create(p);

console.log(h.proto === p); // ⇒ true

// prototypeのnameが使われる h.greet(); // ⇒ I am a proto

// hのnameを設定 h.name = “cat”;

// h自身がnameを持っていれば、プロトタイプではなく自身のnameが使われる h.greet(); // ⇒ I am a cat ```

- [Object.create() - JavaScript | MDN(developer.mozilla.org)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/create)

</markdow n>

ecmascript/class.1758358606.txt.gz · 最終更新: by nullpon