前回からのつづき

前回、データ型の中で、プリミティブ型を中心に説明してきました。今回は、そのつづきとして、オブジェクト型について説明していきたいと思います。


🧊 オブジェクト型

プリミティブ以外はすべてオブジェクトです。オブジェクトは 参照渡しであり、変更可能(mutable)です。


Object

オブジェクトの最も基本的なデータ構造です。

const user = {
  name: "Kitsune",
  age: 20
};

データは、プロパティ名と値の対で記述します。Object の入れ子も可能です。

const user = {
  name: "Kon",
  address: {
    no: "111-1111"
    place: "東京都品川区羽田が丘",
  },
  age: 20
};

JSON との相互変換

Web でのデータの受け渡しに使用する JSON との親和性も高く、相互変換が可能です。

const user = {
  "name": "太郎",
  "age": 30,
  "area": "東京"
};

// オブジェクトをJSONに変換
const jsonString = JSON.stringify(user);
console.log(jsonString); // {"name":"太郎","age":30,"area":"東京"}

// JSONをオブジェクトに変換
const parsedObject = JSON.parse(jsonString);
console.log(parsedObject.name); // 太郎

※ Object の値には、関数も保存可能ですが、JSON に変換された場合、関数は変換されず削除されます。理由は、JSON はデータ交換フォーマットであり、コード(関数)は対象外だからです。


Array

順序付きのリスト構造、つまり配列です。配列オブジェクトの中身は、追加・削除可能です。

const items = ["a", "b", "c"];
items.push("d");

Object オブジェクトとは異なり、個々のデータには、名前が定義されません。しかし、データの位置は保持される為、位置を指定することにより、一意にデータの識別が可能です。

const items = ["a", "b", "c"];
console.log(items[0]); // "a"


Date

日時を扱うためのオブジェクトです。

const now = new Date();
console.log(now.toISOString());

内部的には、「1970/1/1 00:00:00 UTC からの経過ミリ秒(Number 型)」として 64bit 浮動小数点数(IEEE 754 double)で保存されています。

const d = new Date("2026-06-27T12:00:00Z");
console.log(d.valueOf()); // 1782849600000 ← これが内部の実体

Date の限界

Number の限界に依存している為、約 ±27 万年まで表現可能となっています。


RegExp

正規表現を扱うオブジェクトです。

const pattern = /fox/;
console.log(pattern.test("kitsune fox")); // true

文字列の複雑な形式を多岐に表現可能です。

よく使う正規表現(実用サンプル)

1. 数字チェック(整数)
const re = /^[0-9]+$/;

console.log(re.test("12345")); // true
console.log(re.test("12a45")); // false
2. メールアドレス(実用的なバランス型)
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

console.log(re.test("[email protected]")); // true
console.log(re.test("abc@domain"));       // false
3. 日本の電話番号(ハイフンあり・なし両対応)
const re = /^0\d{1,4}-?\d{1,4}-?\d{4}$/;

console.log(re.test("03-1234-5678")); // true
console.log(re.test("0312345678"));   // true
console.log(re.test("123-456"));      // false
4. 郵便番号(日本)
const re = /^\d{3}-?\d{4}$/;

console.log(re.test("123-4567")); // true
console.log(re.test("1234567"));  // true
5. URL の簡易チェック
const re = /^https?:\/\/[^\s/$.?#].[^\s]*$/;

console.log(re.test("https://example.com")); // true
console.log(re.test("ftp://example.com"));   // false
6. 空白を含まない文字列
const re = /^\S+$/;

console.log(re.test("hello world")); // false
console.log(re.test("helloworld"));  // true
7. パスワード強度(英字+数字を含む8文字以上)
const re = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;

console.log(re.test("abc12345")); // true
console.log(re.test("abcdefg"));  // false
8. HTMLタグを除去する
const re = /<[^>]*>/g;

console.log("Hello <b>World</b>".replace(re, "")); // "Hello World"
9. カンマ区切りの数値(1,234,567)
const re = /^\d{1,3}(,\d{3})*$/;

console.log(re.test("1,234,567")); // true
console.log(re.test("1234567"));   // false
10. ひらがなだけ
const re = /^[\u3040-\u309F]+$/;

console.log(re.test("こんにちは")); // true
console.log(re.test("コンニチハ")); // false


ラッパーオブジェクト

JavaScript には「ラッパーオブジェクト」という概念があります。

ラッパーオブジェクトとは、プリミティブ型に、オブジェクトの様なメソッドアクセスを提供する仕組みです。

プリミティブ型に対応する形で、その型に対応するラッパーオブジェクトが存在します。

プリミティブとラッパーオブジェクトの対応表

プリミティブ型 対応するラッパーオブジェクト 自動ボクシングされるか
string String ✔ される
number Number ✔ される
boolean Boolean ✔ される
bigint BigInt ❌ されない
symbol Symbol ❌ されない
undefined なし ❌ されない
null なし ❌ されない

JavaScript では、プリミティブ型を一時的にオブジェクト化することをボクシング( boxing )/ ラッピング( wrapping )と呼びます。

逆に、オブジェクトからプリミティブに戻すことをアンボクシング(unboxing)と呼びます。

以下の 3 つは メソッドを呼ぶときに自動的にラッパーオブジェクトに変換されます。

  • string 型 → String
  • number 型 → Number
  • boolean 型 → Boolean

その為、下記のような処理が可能になります。

console.log((123).toString()); // "123"
console.log("Kitsune".length); // 6
console.log(b.valueOf()); // 1

これらのオブジェクトは、明示的に呼び出すことが可能です。

const n = Number(true);  // 1
const s = String(123); // "123"
const b = Boolean(1); // true

なぜ bigint と symbol が自動ボクシングされないのかというと

  • bigint

BigInt は Number と混ざると危険なので、暗黙の型変換を極力禁止する設計になっています。その為、 Number との混同を避けるためです。

  • symbol

Symbol は「一意の識別子」であり、オブジェクト化すると identity が変わるという問題があるためです。

これらは、比較的新しい型であるある為、“プリミティブ自身がメソッドを持つ” ため、ボクシングする必要がありません。

10n.toString();        // OK(BigInt 自体がメソッドを持つ)
Symbol("x").toString(); // OK(Symbol 自体がメソッドを持つ)

尚、ラッパーオブジェクトとしては、存在するので、下記の使い方は可能です。

console.log(Object(10n));        // BigInt オブジェクト
console.log(Object(Symbol("x"))); // Symbol オブジェクト

よくある誤り

ラッパーオブジェクトは非常に便利ですが、使い方によっては、思わぬ問題を引き起こす可能性がある為、注意が必要です。

ここでは、String オブジェクトを例に説明します。

const s1 = String(123);
const s2 = new String(123);

これらは、一見同じもののように見えます。しかし、下記を実行すると違いがあります。

console.log(s1 == S2); // true
console.log(s1 === S2); // false

この違いは、どこからくるのでしょうか。

実は、String オブジェクトには、使い方によって、下記のような違いがあります。

  • String(関数呼び出し)

→ 値を文字列に変換するための 変換関数

  • new String(コンストラクタ呼び出し)

→ 文字列を包む String オブジェクト を生成する

つまり、s1 は、プリミティブ型、s2 は、オブジェクト型となる為、比較演算子による違いが表れます。

👉 これが、思わぬ比較・条件分岐でのバグの原因になる可能性がある為、基本的には、ラッパーオブジェクトに対し、 new 演算子は使わない方が無難です。

※ Bigint と Symbol への NEW 演算子はエラーになります。


キー・コレクション

ES6(ECMAScript 2015)で追加された、より強力なデータ構造です。実態はオブジェクト型です。

Map

キーにあらゆる値(オブジェクト含む)を使える連想配列です。

const map = new Map();
map.set("name", "Kitsune");
map.set({ id: 1 }, "object key");

キーと値の組み合わせで保持されます。内部的には登録した順序が保持されます。

キーによる値の抽出や、追加・削除が可能です。

Set

重複を許さない集合です。

const set = new Set([1, 2, 2, 3]);
console.log(set); // {1, 2, 3}

Map オブジェクトと異なり、キーを持ちません。登録した順序が保持され、その位置が値を一意に識別します。

WeakMap

基本的には、Map オブジェクトと同様ですが、キーが オブジェクト限定、かつ ガベージコレクションの対象になる点が異なります。

ガベージコレクションとは、使用されなくなったメモリ領域を一定のタイミングで自動で解放しくれる機能です。

const wm = new WeakMap();
let obj = {};
wm.set(obj, "data");

obj = null; // 参照が切れると GC により自動的に破棄される

※ 参照を切るためには、該当キーオブジェクトに null の設定(オブジェクトへの参照の解放)が必要です。

WeakSet

基本的には、Set オブジェクトと同様ですが、オブジェクトのみを保持し、かつ ガベージコレクションの対象になる点が異なります。

ガベージコレクションとは、使用されなくなったメモリ領域を一定のタイミングで自動で解放しくれる機能です。

const ws = new WeakSet();
let o = {};
ws.add(o);

o = null; // 参照が切れると GC により自動的に破棄される

※ 参照を切るためには、該当オブジェクトに null の設定(オブジェクトへの参照の解放)が必要です。


非同期処理( Promise )

ES6(ECMAScript 2015)で追加された Promise は 非同期処理の結果を表すオブジェクトです。

const p = new Promise((resolve, reject) => {
  setTimeout(() => resolve("done"), 1000);
});

p.then(result => console.log(result));

非同期処理をコールバックを使わずに記述できます。その後、追加された async / await と組み合わせると更に読みやすい記述が可能となります。

async function run() {
  const result = await p;
  console.log(result);
}
run();

詳細については、過去記事、モダンJavaScript入門/非同期処理のモダンな書き方を参照してください。

(つづく)