きっかけ
「型を確かめるぜ」ということでこの記事を書いたところ、「それ規格においては型って言わないで?」とコメントで指摘を受け発覚。
やろうとしていたのは、何らかのオブジェクトについて、「それが Array とか Blob とか何なのかを確かめたい!」ってこと。なぜなら typeof
だけだと、number や string はわかるけど、Array や Blob などは全部 object
って出てきてしまうから。
「この object
をもっと詳しく確かめたい!」というのが先の記事の内容になるわけです。ところが、ECMAScript 上では Array型 Blob型 は存在しない ので、全部まとめて型と表現したのは、たしかに誤りだったのです。
改めてしっかり調べ、発見したことを書いていきます。
本当の型は 7種 (+1) だけ
※ 個数は ECMAScript 2024 時点
typeof
演算子によって、任意のオブジェクトのプリミティブ型を知ることができます。
このプリミティブ型が、規格上の本当の型と呼べるものです。
undefined, null, boolean, number, bigint, string, symbol の 7つの型が存在し、それ以外の Array とかは「その他のオブジェクト」ということになります。
冒頭に述べた「Array型 Blob型 は存在しない」というのはこのことです。
function型も存在しない
typeof
に何らかの関数を渡してやると、function
と返ってきます。しかし、ここだけちょっと例外的で、function
型も存在せず、オブジェクトの 1種です。
Array は「標準組み込みオブジェクト」
MDN で Array のページを見てみましょう。
確かに、「Array型」とはどこにもありません。ドキュメントのカテゴリを見てみると、どうやらこれらは「型」でなく「標準組み込みオブジェクト」という区分で呼ぶことができそうです。
下部に仕様書 (ECMAScript) へのリンクが貼られています。覗いてみましょう。
Arrays are exotic objects that give special treatment to a certain class of property names. See 10.4.2 for a definition of this special treatment.
「See 10.4.2」とあって、その 10.4章は・・・「Built-in Exotic Object Internal Methods and Slots」。つまり、「ビルトイン (= 標準で組み込み) のオブジェクト」のようですね (雑解釈)。
その他の標準組み込みオブジェクトもついでに見てみます。
関数もオブジェクトの一種なので、encodeURL()
などの標準関数も「標準組み込みオブジェクト」として載っています。
Blob は・・・API?
再び MDN、今度は Blob を見てみます。
おや、カテゴリが「標準組み込みオブジェクト」ではありません。仕様書の欄は・・・?
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 の実行環境) ができあがるのです。
ちなみに、Ecma International は主に情報関係で、W3C と WHATWG は主に Web 関係で、他にも色々な事項の標準を策定しています。
Ecma International (ECMAScript) により JavaScript の文法は規定されている・・・と記しましたが、CommonJS というプロジェクトによっても JavaScript の規定が作られています。
ブラウザでは ECMAScript を動かすことができ、CommonJS は動きません。
どちらも JavaScript で、基本構文はだいたい同じなのですが、アクセスできる機能などが異なります。誕生した経緯などについては、記事の範囲を超えるので別解説に委ねます。
まとめ
- 本当の型は、オブジェクト除いて 7種だけ
- 関数だとか色々な機能を提供してくれるヤツは全部オブジェクト
- Array とか標準関数とかは「標準組み込みオブジェクト」、あるいは「Web API から提供されているオブジェクト」
JavaScript は策定しているところが 1箇所じゃないとかあって、めっちゃややこしい言語ですねぇ・・・。
もう一点 - プリミティブ型が object に化けるとき
プリミティブ値は、メソッドなどを持ちません。
「・・・あれ?じゃあ文字列に "hello".split()
とかできるやつは何なの?」
あれは、プリミティブラッパーオブジェクトに暗黙的に変換されてから実行されているものです。
/* これはプリミティブ値 */
let v = "hello";
/* メソッド呼んだりしたら暗黙的に変換 */
v.toString();
// 'hello'
(2024/10/23 編集) これ変換されない例と思ってたけど・・・
/* 変換されない例 (・・・って扱いでいいと思う、多分) */
3.toString();
// Uncaught SyntaxError: Invalid or unexpected token
/* 変換される例 */
let v = 3;
v.toString();
// '3'
(追記)
3.
までが数値リテラルと解釈され、その後に toString()
が並んで、「なんか文法違うで?」というエラーだったようです。プリミティブラッパーオブジェクトへ変換されないわけでなく、変換の手前の問題だったようです。
(追記ここまで)
プリミティブラッパーオブジェクトに明示的に変換するには以下の通り。
let obj = new Number(3);
obj.toString();
// '3'
プリミティブラッパーオブジェクトについて、より詳しいことは検索してみてください。(気力切れ)
てか、この言語ほんとに型の話ややこしい・・・。