どうやら僕の中での JavaScript の型に対する認識が違ったらしい

## きっかけ

「型を確かめるぜ」ということでこの記事を書いたところ、「それ規格においては型って言わないで？」とコメントで指摘を受け発覚。

https://qiita.com/aKuad/items/20e3b2c2bd2df2e1cd93

やろうとしていたのは、何らかのオブジェクトについて、「それが Array とか Blob とか何なのかを確かめたい！」ってこと。なぜなら `typeof` だけだと、number や string はわかるけど、Array や Blob などは全部 `object` って出てきてしまうから。

「この `object` をもっと詳しく確かめたい！」というのが先の記事の内容になるわけです。ところが、ECMAScript 上では **Array型 Blob型 は存在しない** ので、全部まとめて型と表現したのは、たしかに誤りだったのです。

改めてしっかり調べ、発見したことを書いていきます。

## 本当の型は 7種 (+1) だけ

※ 個数は ECMAScript 2024 時点

`typeof` 演算子によって、任意のオブジェクトの[プリミティブ型](https://developer.mozilla.org/ja/docs/Glossary/Primitive)を知ることができます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/typeof

このプリミティブ型が、**規格上の本当の型**と呼べるものです。

undefined, null, boolean, number, bigint, string, symbol の 7つの型が存在し、それ以外の Array とかは「その他のオブジェクト」ということになります。

冒頭に述べた「Array型 Blob型 は存在しない」というのはこのことです。

:::note warn
**function型も存在しない**

`typeof` に何らかの関数を渡してやると、`function` と返ってきます。しかし、ここだけちょっと例外的で、**`function` 型も存在せず、オブジェクトの 1種です。**
:::

## Array は「標準組み込みオブジェクト」

MDN で Array のページを見てみましょう。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array

確かに、「Array型」とはどこにもありません。ドキュメントのカテゴリを見てみると、どうやらこれらは「型」でなく「標準組み込みオブジェクト」という区分で呼ぶことができそうです。

下部に仕様書 (ECMAScript) へのリンクが貼られています。覗いてみましょう。

https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array-objects

> Arrays are [exotic objects](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#exotic-object) that give special treatment to a certain class of property names. See [10.4.2](https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-array-exotic-objects) for a definition of this special treatment.

「See 10.4.2」とあって、その 10.4章は･･･「Built-in Exotic Object Internal Methods and Slots」。つまり、「ビルトイン (= 標準で組み込み) のオブジェクト」のようですね (雑解釈)。

その他の標準組み込みオブジェクトもついでに見てみます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects

関数もオブジェクトの一種なので、`encodeURL()` などの標準関数も「標準組み込みオブジェクト」として載っています。

## Blob は･･･API？

再び MDN、今度は Blob を見てみます。

https://developer.mozilla.org/ja/docs/Web/API/Blob

おや、カテゴリが「標準組み込みオブジェクト」ではありません。仕様書の欄は･･･？

https://w3c.github.io/FileAPI/#blob-section

> 3\. The Blob Interface and Binary Data

ECMAScript ではなく W3C というところでの規定のようです。

Web API の 1つ、File API の規定上において、ファイルデータ (バイナリデータ) のやりとりをするインターフェースとなるオブジェクト、的な。

## JavaScript を策定しているとこの話

Ecma International という団体により、JavaScript の文法は規定 (標準化) されています。この団体が発行している仕様書は、ECMAScript 20?? と呼ばれます。(?? は発行年が入り、仕様書のバーションを示している。)

さて、ECMAScript では JavaScript の**文法を**規定していますが、Web API は規定されていません。Web API は、主に W3C と WHATWG という団体によって規定されています。

･･･なんだか色々でてきてややこしいですね。

* 文法の規定は:
  * こう書くと変数になる、関数になる、演算する、それからこう書くとこう動くオブジェクトが最初からある (など)
* Web API の規定は:
  * こういう関数 (またはオブジェクト) があって、そこにこういう引数を入れると、こういうデータやりとりがされる

ブラウザは、ECMAScript に示されている文法に沿って、JavaScript を解釈するように作られます。そこに加えて、Web API で規定されている関数やオブジェクトが、規定の通りに実装されます。

こうして、動きのある Web ページだったり、ファイルの読み込みやデータの送受信ができたりする、ブラウザ (JavaScript の実行環境) ができあがるのです。

:::note
ちなみに、Ecma International は主に情報関係で、W3C と WHATWG は主に Web 関係で、他にも色々な事項の標準を策定しています。
:::

:::note
Ecma International (ECMAScript) により JavaScript の文法は規定されている･･･と記しましたが、CommonJS というプロジェクトによっても JavaScript の規定が作られています。

ブラウザでは ECMAScript を動かすことができ、CommonJS は動きません。

どちらも JavaScript で、基本構文はだいたい同じなのですが、アクセスできる機能などが異なります。誕生した経緯などについては、記事の範囲を超えるので別解説に委ねます。
:::

## まとめ

* 本当の型は、オブジェクト除いて **7種だけ**
* 関数だとか色々な機能を提供してくれるヤツは全部**オブジェクト**
* Array とか標準関数とかは「**標準組み込みオブジェクト**」、あるいは「**Web API から提供されているオブジェクト**」

JavaScript は策定しているところが 1箇所じゃないとかあって、めっちゃややこしい言語ですねぇ･･･。

## もう一点 - プリミティブ型が object に化けるとき

プリミティブ値は、**メソッドなどを持ちません。**

「･･･あれ？じゃあ文字列に `"hello".split()` とかできるやつは何なの？」

あれは、**プリミティブラッパーオブジェクト**に暗黙的に変換されてから実行されているものです。

```js
/* これはプリミティブ値 */
let v = "hello";

/* メソッド呼んだりしたら暗黙的に変換 */
v.toString();
// 'hello'
```

<details><summary>(2024/10/23 編集) これ変換されない例と思ってたけど･･･</summary>

```js
/* 変換されない例 (･･･って扱いでいいと思う、多分) */
3.toString();
// Uncaught SyntaxError: Invalid or unexpected token

/* 変換される例 */
let v = 3;
v.toString();
// '3'
```

(追記)

@juner さんより、[コメント](https://qiita.com/aKuad/items/8b90b0611d5bb505236a#comment-bcf06f9c4012e3f54e22)にて指摘いただきました。

`3.` までが数値リテラルと解釈され、その後に `toString()` が並んで、「なんか文法違うで？」というエラーだったようです。プリミティブラッパーオブジェクトへ変換されないわけでなく、変換の手前の問題だったようです。

(追記ここまで)

---

</details>

プリミティブラッパーオブジェクトに明示的に変換するには以下の通り。

```js
let obj = new Number(3);
obj.toString();
// '3'
```

プリミティブラッパーオブジェクトについて、より詳しいことは検索してみてください。(気力切れ)

てか、この言語ほんとに型の話ややこしい･･･。