---
type: learn
language: javascript
slug: object/nested
title: "入れ子のオブジェクトを安全に扱う"
title_tag: "JavaScript 入れ子の値を安全に取る — ?. と ?? 【第2回】"
summary: >
  深いところを辿ると途中で落ちます。オプショナルチェーンで落ちないようにする方法、
  分割代入で必要な値だけ取り出す書き方、既定値の付け方と ?? と || の違いを確かめます。
description: >
  data.user.address.city の途中で落ちる理由と、?. で防ぐ書き方。0 や空文字を消してしまう
  || の罠と ?? との違い、分割代入での既定値と改名まで実行して確かめられます。
status: published
difficulty: 2
minutes: 9

versions:
  verified: "Node 22.22.3"
  since: "ES2020"
  deprecated: null
  removed: null

sources:
  - title: "Optional Chains — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-optional-chains"
  - title: "Destructuring Binding Patterns — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-destructuring-binding-patterns"
  - title: "Nullish coalescing operator — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing"

terms: [オプショナルチェーン, Null 合体, 分割代入, 既定値]

links:
  prev: javascript/learn/object/basics
  next: javascript/learn/object/iterate
  related:
    - javascript/errors/cannot-read-properties-of-undefined
    - javascript/how-to/object/merge
    - javascript/reference/function/parameters

content_updated_at: 2026-09-08
published_at: 2026-09-08
---

実際のデータは入れ子になっています。深く辿るのは、そのままだと危険です。

```js run
const data = { user: { profile: { name: 'あ' } } };

console.log(data.user.profile.name);
```
```output
あ
```

**途中の鍵が無いと落ちます。**

```js bad
const data = { user: { profile: { name: 'あ' } } };

console.log(data.user.address.city);
```
```output
TypeError: Cannot read properties of undefined (reading 'city')
```

`data.user.address` が `undefined` で、その `city` を読もうとしたからです。
[key:落ちるのは最後の1段]で、原因はその手前にあります。
→ [Cannot read properties of undefined](/ja/javascript/errors/cannot-read-properties-of-undefined/)

## `?.` で落ちないようにする

`?.` は、[key:左が `null` か `undefined` なら、そこで止めて `undefined` を返します]。

```js run
const data = { user: { profile: { name: 'あ' } } };

console.log(data.user?.address?.city);
console.log(data.user?.profile?.name);
```
```output
undefined
あ
```

これを[type:オプショナルチェーン]と呼びます。

**止まるのは `null` と `undefined` のときだけ**です。
`0` や空文字では止まりません。

```js run
const data = { count: 0, label: '' };

console.log(data.count?.toFixed(1));
console.log(data.label?.length);
```
```output
0.0
0
```

### 関数と配列にも使える

```js run
const api = { load: () => 'あ' };

console.log(api.load?.());
console.log(api.save?.());

const list = null;

console.log(list?.[0]);
```
```output
あ
undefined
undefined
```

`?.()` は「[key:関数があれば呼ぶ]」、`?.[]` は「あれば取り出す」です。
**無い関数を呼んでも落ちません。**

### 使いすぎない

```js bad
console.log(data?.user?.profile?.name);
```

**全部に付けるのは、考えるのをやめている合図です。**
`data` が必ずあると分かっているなら、そこに `?.` は要りません。

[bad:本当は「無いはずがない」ところが `undefined` になっていても、`?.` が黙って隠します。]
付けるのは「[em:無いことがありうる]」と分かっている場所だけにしてください。

## 既定値を付ける

`??` は、[key:左が `null` か `undefined` のときだけ]右を返します。

```js run
const data = { user: {} };

console.log(data.user?.address?.city ?? '未設定');
```
```output
未設定
```

### `||` との違い

**ここは必ず踏む落とし穴です。**

```js run
const settings = { count: 0, label: '', flag: false };

console.log(settings.count ?? 10, settings.count || 10);
console.log(JSON.stringify(settings.label ?? 'なし'), JSON.stringify(settings.label || 'なし'));
console.log(settings.flag ?? true, settings.flag || true);
```
```output
0 10
"" "なし"
false true
```

`||` は[bad:`0`・空文字・`false` も「無い」と見なします]。

- 件数が `0` なのに `10` になる
- 入力が空なのに「なし」に置き換わる
- 設定を `false` にしたのに `true` になる

**「値が無いとき」の既定値は `??`、「偽のとき」の代替は `||`。**
迷ったら `??` です。

## 分割代入で取り出す

必要な値だけを、名前を付けて取り出せます。

```js run
const user = { name: 'あ', age: 20, address: { city: '東京' } };

const { name, age } = user;

console.log(name, age);
```
```output
あ 20
```

入れ子も取り出せます。

```js run
const user = { name: 'あ', address: { city: '東京' } };

const { address: { city } } = user;

console.log(city);
```
```output
東京
```

[bad:ただし `address` が無いと落ちます。] 深い分割代入は、
**あることが確実なときだけ**にしてください。

### 名前を変える・既定値を付ける

```js run
const user = { name: 'あ' };

const { name: userName, nothing = '既定値' } = user;

console.log(userName);
console.log(nothing);
```
```output
あ
既定値
```

- `name: userName` … [fn:別の名前で受け取る]。他の変数と衝突するときに使う
- `nothing = '既定値'` … **無いときだけ**使われる

既定値が働くのは[key:`undefined` のとき]だけです。`null` では働きません。

```js run
const user = { a: null, b: undefined };

const { a = '既定値', b = '既定値' } = user;

console.log(a);
console.log(b);
```
```output
null
既定値
```

**`??` は `null` でも働き、分割代入の既定値は働きません。** ここが違います。

## 関数の引数で使う

分割代入がいちばん効くのは、関数の受け口です。

```js run
function show({ name, city = '不明' }) {
  return `${name}（${city}）`;
}

console.log(show({ name: 'あ', city: '東京' }));
console.log(show({ name: 'い' }));
```
```output
あ（東京）
い（不明）
```

**何を使うのかが、呼び出し側から見えます。**
引数の順番を覚えなくてよくなるのも利点です。

## まとめ

- 途中の鍵が無いと落ちる。**原因は落ちた場所の手前**
- `?.` は[key:`null` と `undefined` のときだけ]止まる。`0` や空文字では止まらない
- **全部に `?.` を付けない。** 隠すべきでない間違いまで隠れる
- 既定値は `??`。**`||` は `0`・空文字・`false` も置き換える**
- 分割代入の既定値は `undefined` のときだけ働く（`null` では働かない）
- 関数の引数で使うと、**何を使うのかが呼び出し側から見える**

## 次に学ぶ

オブジェクトの中身を[key:全部まとめて]扱う方法を学びます。
`Object.keys()` / `values()` / `entries()` で回し、
配列のメソッドと組み合わせて変換する形までやります。

→ [第3回: オブジェクトを回す・変換する](/ja/javascript/learn/object/iterate/)
