【入門編】 値オブジェクト(Value Object)の作成 – JavaScript実践ガイド

こんにちは!フロントエンドの現場を長年うろついているチーフアーキテクトです。

JavaScriptのコードを書いているとき、「あれ?さっきは文字列だったはずの変数に、いつの間にか数値が混ざってバグってる……!」なんて冷や汗をかいた経験、ありませんか? 大丈夫です、それ、世界中のすべてのプログラマーが通る道ですから安心してください。

今日は、そんなJavaScriptの「型のゆらぎ」から私たちのコードを守り、さらにアプリの設計を劇的に美しくしてくれる「値オブジェクト(Value Object)」という秘密兵器について、お話ししようと思います。

難しい専門用語はなるべく抜きにして、身近な「お買い物」のイメージから優しく紐解いていきましょう!

—

そもそも「値オブジェクト」ってなに?

いきなりコードを書く前に、身の回りのもので考えてみましょう。

例えば、お財布に入っている「1,000円札」を思い浮かべてください。
ただの紙切れですが、そこには「1,000円であること」という絶対的な価値と意味が宿っていますよね。もし裏に落書きをしても、破れていなければ価値は1,000円のままです。

プログラミングの世界でも同じです。
私たちが何気なく使う「メールアドレス」や「年齢」「価格」といったデータは、ただの「文字(String)」や「数字(Number)」ではありません。

  • メールアドレスなら、「アットマーク(@)が含まれているか?」というルールがある。
  • 年齢なら、「マイナスになってはいけない」というルールがある。

こうした「データのルールや意味」を、ひとつの頑丈なカプセル(クラス)に閉じ込めてしまおう! というのが、値オブジェクトの考え方です。

—

なぜJavaScriptで値オブジェクトが必要なの?

JavaScriptは、とても自由で優しい言語です。変数になんでも入れられるし、型のチェックもゆるふわです。
でも、その「優しさ」が、実務の現場では時々牙を剥きます。

例えば、ECサイトで商品の価格を計算する機能を考えてみましょう。

// 普通によくある書き方
let price = 1000; // 1000円

// うっかり文字列が混ざっちゃった!
price = “1000円”;

// 割引計算をすると……あれ?
let discounted = price – 100; // “1000円” – 100 = ??? (NaNになっちゃう!)

JavaScriptのエンジンは、「”1000円”から100を引けと言われたから頑張ってみたけど、無理だった……」と、頭を抱えてしまいます(これが`NaN`という絶望の合図ですね)。

こういう「不正なデータがいつの間にか入り込んでアプリをクラッシュさせる魔物」を退治するために、値オブジェクトが役に立ちます。

—

実践!「金額」を表す値オブジェクトを作ってみよう

それでは実際に、JavaScriptのクラスを使って、お買い物で使える安全な「価格(Money)」の値オブジェクトを作ってみましょう。

エディタを開く準備はいいですか? 一緒に見ていきましょうね。

/

  • 金額を表す値オブジェクト(Value Object)

/
class Price {
// 内部で保持する実際の数値
#value;

constructor(amount) {
// 1. ルールチェック:数値じゃなかったら怒る!
if (typeof amount !== “number”) {
throw new Error(“価格は数値で指定してくださいね。”);
}

// 2. ルールチェック:マイナスだったら怒る!
if (amount < 0) { throw new Error("価格にマイナスは指定できません。"); } // 3. ルールチェック:小数点以下が変だったら丸めるなどの処理を入れることも this.#value = amount; } // 値を取り出すためのメソッド(ゲッター) get value() { return this.#value; } // 表示用のフォーマットを作るメソッド(ドメインロジックの同梱) toDisplayString() { return `¥${this.#value.toLocaleString()}`; } // 足し算をするメソッド(不変性を守るため、新しいオブジェクトを返すのがコツ!) add(otherPrice) { // 他のPriceクラスのインスタンスかどうかチェックするとさらに安全 if (!(otherPrice instanceof Price)) { throw new Error("足し算できるのはPrice同士だけです。"); } return new Price(this.#value + otherPrice.value); } } // ========================================== // 実際に使ってみましょう! // ========================================== try { // 正しい使い方の例 const applePrice = new Price(120); // りんご代 120円 const orangePrice = new Price(150); // みかん代 150円 console.log(applePrice.toDisplayString()); // 出力: ¥120 // 合計を計算する const totalPrice = applePrice.add(orangePrice); console.log(totalPrice.toDisplayString()); // 出力: ¥270 // ⚠️ やってはいけないこと(不正な値)のテスト // const weirdPrice = new Price(-50); // => エラー:「価格にマイナスは指定できません。」
// const stringPrice = new Price(“120円”); // => エラー:「価格は数値で指定してくださいね。」

} catch (error) {
console.error(“エラーが発生しました:”, error.message);
}

コードのポイント解説

1. カプセル化(`#value`)
クラスの頭に付いている `#` は、JavaScriptの最新機能である「プライベートフィールド」です。外から直接 `price.#value = 9999` のように書き換えられないよう、ガッチリ鍵をかけています。
2. 不変性(Immutability)
一度作った `Price` オブジェクトの中身を後から変更することはできません。もし金額を変えたくなったら、新しく `new Price(…)` を作り直します。これにより、「いつの間にか値が変わっていた」というバグが根絶やしにされます。
3. 振る舞い(メソッド)の同居
単なるデータだけでなく、「表示用の文字列にする方法(`toDisplayString`)」や「足し算のルール(`add`)」をデータの近くに持たせています。これにより、「あっちのファイルでもこっちのファイルでも、同じ金額のフォーマット書き方をしてバグる」という悲劇を防げます。

—

まとめ:あなたのコードを「優しく、強く」する設計へ

今回は、値オブジェクトの基本と、JavaScriptでの実装方法についてお伝えしました。

最初は「たかが数字をクラスで包むなんて、コード量が増えてめんどくさいな」と感じるかもしれません。大丈夫、私も最初はそう思っていました(笑)。

ですが、アプリの規模が大きくなればなるほど、この「小さな安全の積み重ね」が、将来のあなたやチームメンバーの夜勤を救うことになります。

JavaScriptの自由な世界を楽しみつつ、大切なデータにはちょっとだけ厳格な「お守り」を持たせてあげてくださいね。それでは、また次回のモダンフロントエンドの旅でお会いしましょう!

コメント

タイトルとURLをコピーしました