💡

【JavaScript】配列ってオブジェクトの仲間ってことに気づいた話

2022/10/08に公開

前置き

ある日、いつものようにせっせとコーディングをしていました。この日はバックエンドから受け取った値を色々処理していました。まさにjson色付け係ですね。
そんな最中、こういう形のjsonを受け取りました。

{
    "user-name": "太郎",
  "user-age": 28
}

あっれ、これプロパティ呼び出したいときどうすんだ?

このjsonをdataって変数で定義したとして、もしプロパティがnameageとかだったら

console.log(data.name);
// 太郎

って呼び出せる。でもjsって基本的に-(ハイフン)は変数名で使っちゃいけないし、カンマでプロパティ呼び出してもハイフンのとこで怒られるし、、

console.log(data.user-name);
//                   ^^

どうすんの????

はい、別の呼び出し方があります。オブジェクトに[プロパティ名]をつけることでカンマの方法と同様に呼び出すことができます。

const data = {
  'user-name': '太郎',
  'use-age': 28,
};

console.log(data['user-name']);
// 太郎

なるほど、こういう呼び出し方もあるのですね。

本題

待ってください、この呼び出し方なんか見たことありますね。

const arr = ['りんご', 'みかん', 'ぶどう'];

console.log(arr[0]);
// りんご

はい、いつもの配列の要素の呼び出し方ですね。
引数を指定すると対象の要素が呼び出されます。

あれ、さっきのオブジェクトのプロパティの呼び出し方を利用したら、オブジェクトの書き方で配列みたいなものを作れるんじゃないか??

結論、作れます。

const obj = {
  0: 'りんご',
  1: 'みかん',
  2: 'ぶどう',
};

console.log(obj[0]);
// りんご

こんな感じでプロパティを数字で並べればまさに配列で要素を呼ぶようなやり方で呼び出しができます。
(ただし、mapなどの配列操作は使えません)

const newObj = obj.map((ele) => ele + 'が好き');
// TypeError: obj.map is not a function

上記はこんなことができるよって例なのですが、JavaScriptは本質的に配列とオブジェクトを同じグループのものとして扱います。
JavaScriptは、動的型付け言語であり、大きくプリミティブ型とオブジェクト型の2種類に分類されます。
(動的型付け言語とか、プリミティブ型って何?って話はここでは割愛します。)
そして、オブジェクト型というのは以下の3つのリテラルに分類されます。

  • 配列リテラル
    ...... [1, 2, 3] の形式で記述する。[] は空の配列を示す。 arr[n] という構文で n + 1 番めの要素にアクセスできる。Arrayオブジェクトのインスタンスとして生成される。
  • オブジェクトリテラル
    ...... { key: value } の形式で記述する。キーには文字列またはシンボルが用いられる(なお数値を指定すると、自動的に文字列に変換される)。任意のプロパティ値にアクセスするには obj[key] または obj.key の2つの構文が利用できる。 Objectオブジェクトのインスタンスとして生成される。
  • 正規表現リテラル
    ...... /pattern/flagsの形式で記述する。正規表現パターンでの特殊文字の使い方は、他の言語とほぼ 共通。 RegExpオブジェクトのインスタンスとして生成される。

つまり、我々が「配列」、「オブジェクト」と言ってるものは、オブジェクト型変数の「配列リテラル」、「オブジェクトリテラル」のことになります。
また、これらオブジェクト型のリテラルは、その継承元にObjectという標準組み込みオブジェクトを持ってたりします。

console.log(obj.__proto__.constructor.name);
// Object
console.log(arr.__proto__.__proto__.constructor.name);
// Object

ちなみに、配列リテラルはArrayというオブジェクトを持っていますが、Objectオブジェクトよりも手前で呼び出されるので、配列リテラルも大元はオブジェクトリテラルなのがわかります。

console.log(arr.__proto__.constructor.name);
// Array

おわりに

結局はオブジェクトから来てるんですね。
だからってどうってことないんですけど、こういう大元の仕組みを知ってることで理解が深まったりしますよね。

参考

りあクト! TypeScriptで始めるつらくないReact開発 第4版【① 言語・環境編】

Discussion