オブジェクトの基本 — JavaScript Tips
オブジェクトは キーと値の集まり です。プロパティの読み書き、メソッド、参照の等価、Object.keys あたりが日常の操作になります。
参考: MDN — オブジェクト · MDN — オブジェクト初期化子 · MDN — プロパティ
目次
オブジェクトリテラル
{ } でオブジェクトを作ります。
const user = { name: "太郎", age: 30, active: true,};console.log(user.name); // 太郎変数名と同じキーは省略できる(短縮記法)
const name = "花子";const age = 25;const profile = { name, age };// { name: "花子", age: 25 } と同じ計算されたプロパティ名
const field = "score";const record = { [field]: 100, [`${field}_max`]: 100,};// { score: 100, score_max: 100 }オブジェクトは 参照型 です。変数には「中身のコピー」ではなく「オブジェクトへの参照」が入ります。
プロパティの読み書き
ドット記法とブラケット記法
const book = { title: "JS入門", year: 2024 };book.title; // "JS入門"book["title"]; // "JS入門"const key = "year";book[key]; // 2024(キーが変数のときはブラケット)存在しないプロパティは undefined になります。
book.publisher; // undefined追加・更新・削除
book.publisher = "Example Press";book.year = 2025;delete book.active; // あれば削除(この例ではもともと無い)const で宣言したオブジェクトでも プロパティの変更は可能 です(再代入だけ不可)。
const config = { debug: false };config.debug = true; // OKメソッド
プロパティの値に関数を入れたものがメソッドです。短縮記法で書けます。
const counter = { value: 0, increment() { this.value += 1; return this.value; }, reset() { this.value = 0; },};counter.increment(); // 1counter.increment(); // 2counter.reset();this は 呼び出し方 で変わります。メソッドとして counter.increment() のように呼べば、this は counter を指します。アロー関数をメソッドにすると this が期待とずれることがあるため、オブジェクトのメソッドは通常の function 短縮記法が無難です。
const math = { add(a, b) { return a + b; },};console.log(math.add(2, 3)); // 5参照と等価
=== は 同じ参照か を見ます。中身が同じ別オブジェクトは等しくありません。
const a = { x: 1 };const b = { x: 1 };const c = a;console.log(a === b); // false(別オブジェクト)console.log(a === c); // true(同じ参照)c.x = 99;console.log(a.x); // 99(a も変わる)flowchart LR subgraph heap["メモリ上のオブジェクト"] O["{ x: 99 }"] end a["変数 a"] --> O c["変数 c"] --> O b["変数 b"] --> O2["{ x: 1 }(別インスタンス)"]配列もオブジェクト
[1, 2] === [1, 2]; // false中身まで比較するにはループや JSON.stringify(制限あり)、専用ライブラリなどが必要です。学習段階では「オブジェクト比較は参照」と覚えるのが先です。
Object.keys などの基本操作
組み込みの Object 静的メソッドで、キーや値を列挙できます。
const product = { id: "P001", name: "ノート", price: 500,};Object.keys(product); // ["id", "name", "price"]Object.values(product); // ["P001", "ノート", 500]Object.entries(product); // [["id","P001"], ["name","ノート"], ["price",500]]ループとの組み合わせ
for (const key of Object.keys(product)) { console.log(key, product[key]);}for (const [key, value] of Object.entries(product)) { console.log(`${key}: ${value}`);}| メソッド | 返すもの |
|---|---|
Object.keys(obj) |
自身の列挙可能なキーの配列 |
Object.values(obj) |
値の配列 |
Object.entries(obj) |
[キー, 値] の配列 |
プロパティの有無
"price" in product; // trueproduct.hasOwnProperty("id"); // true(プロトタイプチェーンを除く)in はプロトタイプ鎖上も見ます。自分が定義したプロパティだけなら hasOwnProperty や Object.hasOwn(モダン)を使います。
Object.hasOwn(product, "name"); // trueスプレッドと浅いコピー
オブジェクトのコピーやマージにスプレッド構文を使います。
const defaults = { theme: "light", lang: "ja" };const userPrefs = { lang: "en", fontSize: 14 };const merged = { ...defaults, ...userPrefs };// { theme: "light", lang: "en", fontSize: 14 }// 後から書いた lang が優先浅いコピーであることに注意
const original = { meta: { version: 1 },};const copy = { ...original };copy.meta.version = 2;console.log(original.meta.version); // 2(ネストは共有)深いコピーが必要なら、構造が単純なうちは手で書くか、学習が進んでから専用手段を検討します。
凍結(再代入・プロパティ変更の防止)
const frozen = Object.freeze({ id: 1 });// frozen.id = 2; // 厳格モードではエラー、緩いモードでは無視よくある失敗
| 症状 | 原因 | 対処 |
|---|---|---|
プロパティが undefined |
typo、存在しないキー | キー名を確認。オプショナルチェーン obj?.key |
| 変更したのに別変数が変わらない | 参照の共有を理解していない | コピーが必要ならスプレッドで新オブジェクトを作る |
=== で同じ内容なのに false |
参照比較 | 意図どおり。中身比較は別ロジック |
Object.keys に想定外のキー |
プロトタイプ由来 | hasOwn / hasOwnProperty でフィルタ |
| スプレッド後もネストが共有 | 浅いコピー | ネストごとコピーするか設計を見直す |
メソッド内の this が undefined |
メソッドを変数に抜いて呼んだ | call / bind で束縛するか、呼び出し方を見直す |