概要
JavaScript の組み込みオブジェクトには、
newを使ってインスタンスを生成するものと、
newを使わずそのまま利用するものが存在します。
これらの違いは、メソッドがどこに定義されているかという点に集約されます。
つまり、
new を使える組み込みオブジェクトと、new を使えない組み込みオブジェクトでは、
メソッドが定義されている「場所」が決定的に異なる
ということです。
この記事では、
-
Date/Mapのような new を使える関数オブジェクト -
JSON/Mathのような new を使えない通常のオブジェクト
について、構造レベルでの違いを整理します。
目次
全体像
① new を使える組み込みオブジェクト(Date / Map など)
→ メソッドは prototype に定義されている(インスタンスメソッド)
② new を使えない組み込みオブジェクト(JSON / Math など)
→ メソッドはオブジェクト自身に定義されている(static メソッド)
new を使える組み込みオブジェクトの構造
Date / Map の正体
typeof Date; // "function"
typeof Map; // "function"
- 関数オブジェクト
-
[[Construct]]を持つ -
newが使える -
prototypeを持つ
これらは コンストラクタとして設計された関数オブジェクトです。
Map の内部構造
Map // コンストラクタ(関数オブジェクト)
├─ prototype ──▶ Map.prototype
│ ├─ set()
│ ├─ get()
│ ├─ has()
│ └─ delete()
実際の使用例
const map = new Map();
map.set("a", 1);
このとき JavaScript は次の順で処理します。
-
map自身にsetプロパティがあるかを確認 -
map.__proto__ === Map.prototypeを参照 -
Map.prototype.setを実行 -
thisはmapを指す
この結果、データ(状態)は map インスタンスに保存されます。
prototype に定義されていることの確認
Map.prototype.hasOwnProperty("set"); // true
map.hasOwnProperty("set"); // false
-
setはインスタンス自身には存在しない -
Map.prototypeに定義されている
Date も同様の構造
Date.prototype.getFullYear();
Date.prototype.toISOString();
const d = new Date();
d.getFullYear(); // prototype メソッド
なぜ prototype に置くのか
- 全インスタンスで同じ関数を共有できる
- メモリ効率が良い
- オブジェクト指向設計に沿っている
1000 個の Map インスタンス
→ set / get 関数は 1 つだけ
new を使えない組み込みオブジェクトの構造
JSON / Math の正体
typeof JSON; // "object"
typeof Math; // "object"
- 通常のオブジェクト
- インスタンスを生成しない
- prototype を使った設計ではない
JSON の内部構造(概念)
JSON
├─ stringify()
├─ parse()
使用例
JSON.stringify(obj);
JSON.parse(str);
-
JSON自身が完成形 -
thisを使わない - 状態を持たない
Math も同様
Math.max(1, 2, 3);
Math.random();
Math.hasOwnProperty("max"); // true
このように、メソッドは prototype ではなく、オブジェクト自身に定義されています。
両者の違いの整理
| 観点 | Date / Map | JSON / Math |
|---|---|---|
| typeof | function | object |
| new | 使用可能 | 使用不可 |
| prototype | あり | なし |
| メソッドの定義場所 | prototype | オブジェクト自身 |
| this | インスタンス | 使用しない |
| 状態 | インスタンスに保持 | なし |
Map.set はどこに定義されているのか
Map 自体に set が定義されているわけではありません。
Map.set; // undefined
実際に定義されているのは prototype 側です。
Map.prototype.set; // function
正しい理解は次の通りです。
Map は「設計図」
set / get は Map.prototype に定義されている
実際のデータは map(インスタンス)に保存される