JavaScriptの三項演算子(正式名称:条件演算子)は、条件 ? 真の値 : 偽の値 という構文で、if-else文をコンパクトに書ける演算子です。変数への代入やテンプレートリテラル内など、式が求められる場所で条件分岐を行いたいときに特に威力を発揮します。
この記事では、三項演算子の基本構文からif-elseとの書き比べ、実務で頻出するパターン、ネスト(入れ子)の扱い方、短絡評価(&& / ||)との使い分け、そしてよくあるミスまで体系的に解説します。
この記事で学べること
- 三項演算子の基本構文とif-elseとの違い
- 変数代入・テンプレートリテラル・JSXなど実務で使うパターン
- ネスト(入れ子)の書き方と避けるべき理由
- 短絡評価(&& / ||)やNull合体演算子(??)との使い分け
- よくあるミスと注意点
三項演算子の基本構文
三項演算子は、JavaScript唯一の3つのオペランドを取る演算子です。「三項」という名前はこの特徴に由来します。
基本構文
// 三項演算子の基本構文
条件式 ? 真の場合の値 : 偽の場合の値
条件式が truthy(真と評価される値)なら ? の後ろの値が返され、falsy(偽と評価される値)なら : の後ろの値が返されます。
JavaScript
const age = 20;
const message = age >= 18 ? '成人です' : '未成年です';
console.log(message); // "成人です"
三項演算子は式(expression)であり、値を返します。一方、if-elseは文(statement)であり、値を返しません。この違いが使い分けの鍵です。
if-else文との書き比べ
同じロジックをif-else文と三項演算子で書き比べてみましょう。
if-else文で書いた場合
const score = 75;
let result;
if (score >= 60) {
result = '合格';
} else {
result = '不合格';
}
console.log(result); // "合格"
三項演算子で書いた場合
const score = 75;
const result = score >= 60 ? '合格' : '不合格';
console.log(result); // "合格"
ポイント:三項演算子を使うと、let → const に変更できるケースが多くあります。constを使えば変数が再代入されないことが保証され、コードの安全性と可読性が向上します。
if-else文と三項演算子の違い
| 項目 |
if-else文 |
三項演算子 |
| 種類 |
文(statement) |
式(expression) |
| 値を返す |
返さない |
返す |
| 変数宣言 |
letが必要になりやすい |
constで宣言できる |
| 複数の処理 |
ブロック内で自由に書ける |
1つの式のみ |
| 可読性 |
複雑な条件でも読みやすい |
シンプルな条件向き |
| 使える場所 |
文が書ける場所 |
式が書ける場所すべて |
「式」と「文」の違いが最も重要です。三項演算子は式なので、変数の右辺、関数の引数、テンプレートリテラルの中、JSXの中など、値が必要なあらゆる場所に書くことができます。
実務でよく使うパターン
三項演算子が実際のプロジェクトでどのように使われるか、頻出パターンを見ていきましょう。
パターン1:変数への条件付き代入
最も基本的な使い方です。条件に応じて異なる値を変数に代入します。
JavaScript
// ユーザーの権限に応じたリダイレクト先
const redirectUrl = user.isAdmin ? '/admin/dashboard' : '/user/home';
// 在庫状況の表示テキスト
const stockText = stock > 0 ? '在庫あり' : '在庫切れ';
// 割引の適用
const price = isMember ? basePrice * 0.9 : basePrice;
// 配列の要素数に応じたメッセージ
const label = items.length === 1 ? '1 item' : `${items.length} items`;
パターン2:関数の引数に直接使う
関数を呼び出すときに、引数を条件で切り替えたい場合に便利です。
JavaScript
// classList の切り替え
element.classList.add(isActive ? 'active' : 'inactive');
// console.log の条件付き出力
console.log(isValid ? 'バリデーション成功' : 'バリデーション失敗');
// fetch の URL を条件で切り替え
const response = await fetch(
isDev ? 'http://localhost:3000/api' : 'https://api.example.com'
);
パターン3:テンプレートリテラル内で使う
テンプレートリテラル(`...${...}`)の ${} 内では式しか書けないため、三項演算子が活躍します。
JavaScript
const userName = '田中太郎';
const isLoggedIn = true;
// テンプレートリテラル内での条件分岐
const greeting = `こんにちは、${isLoggedIn ? userName : 'ゲスト'}さん`;
console.log(greeting);
// HTML文字列の動的生成
const html = `
<div class="card">
<h2>${title}</h2>
${imageUrl ? `<img src="${imageUrl}" alt="${title}">` : ''}
<p>${description}</p>
</div>
`;
パターン4:JSXでの条件レンダリング(React)
Reactでは、JSX内でif文を直接書くことができません。そのため、三項演算子が条件付きレンダリングの定番パターンになっています。
React(JSX)
function UserGreeting({ isLoggedIn, userName }) {
return (
<div>
{isLoggedIn ? (
<p>ようこそ、{userName}さん</p>
) : (
<p>ログインしてください</p>
)}
</div>
);
}
// ボタンの表示テキストを切り替え
function ToggleButton({ isOpen, onClick }) {
return (
<button onClick={onClick}>
{isOpen ? '閉じる' : '開く'}
</button>
);
}
JSXでは {} の中に式しか書けません。if文は文なので使えませんが、三項演算子は式なのでそのまま埋め込めます。これがReactで三項演算子が多用される理由です。
パターン5:デフォルト値の設定(?? との違い)
三項演算子はデフォルト値の設定にも使えますが、ES2020で追加されたNull合体演算子(??)の方が適切なケースがあります。
JavaScript
// 三項演算子でデフォルト値を設定
const displayName = user.name ? user.name : '匿名ユーザー';
// Null合体演算子(??)で書いた場合
const displayName = user.name ?? '匿名ユーザー';
// 重要な違い:falsy値の扱い
const count = 0;
// 三項演算子: 0はfalsyなのでデフォルト値が使われる
const result1 = count ? count : 10;
console.log(result1); // 10(意図しない結果)
// ??: nullとundefinedのみデフォルト値が使われる
const result2 = count ?? 10;
console.log(result2); // 0(意図通り)
注意:0、""(空文字列)、falseをfalsy値として扱いたくない場合は、三項演算子ではなくNull合体演算子(??)を使いましょう。?? は null と undefined のみをチェックします。
パターン6:オブジェクトのプロパティで使う
オブジェクトリテラル内でプロパティの値を条件分岐するパターンです。API リクエストのパラメータ構築などで頻出します。
JavaScript
// APIリクエストのパラメータ
const params = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': token ? `Bearer ${token}` : '',
},
body: JSON.stringify(data),
};
// CSSクラス名の組み立て
const buttonStyle = {
backgroundColor: isPrimary ? '#0284c7' : '#6b7280',
cursor: isDisabled ? 'not-allowed' : 'pointer',
opacity: isDisabled ? 0.5 : 1,
};
パターン7:return文で直接使う
関数のreturn文で三項演算子を使うと、条件に応じた値を簡潔に返せます。
JavaScript
// 数値のフォーマット
function formatNumber(num) {
return num >= 10000
? `${(num / 10000).toFixed(1)}万`
: num.toLocaleString();
}
console.log(formatNumber(1500)); // "1,500"
console.log(formatNumber(25000)); // "2.5万"
// 偶数・奇数の判定
const isEven = (n) => n % 2 === 0 ? '偶数' : '奇数';
三項演算子のネスト(入れ子)
三項演算子は入れ子にすることで、3つ以上の条件分岐を表現できます。ただし、可読性とのトレードオフに注意が必要です。
ネストの書き方
三項演算子の :(偽の場合)の部分に、さらに三項演算子を書くことでネストができます。
JavaScript
// 成績の評価(ネストあり)
const score = 85;
const grade = score >= 90 ? 'A'
: score >= 80 ? 'B'
: score >= 70 ? 'C'
: score >= 60 ? 'D'
: 'F';
console.log(grade); // "B"
上記のように、各 : の後ろに改行とインデントを揃えて書くと、比較的読みやすくなります。これは if-else if-else チェーンに相当する書き方です。
同等の if-else文
let grade;
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else if (score >= 70) {
grade = 'C';
} else if (score >= 60) {
grade = 'D';
} else {
grade = 'F';
}
ネストを避けるべき理由と代替手段
ネストされた三項演算子は、2段階までなら許容されるケースもありますが、3段階以上になると急激に可読性が低下します。多くのプロジェクトのESLintルールでもネストは禁止されています。
注意:ESLintの no-nested-ternary ルールを有効にしているプロジェクトでは、三項演算子のネストはエラーになります。チームのコーディング規約を確認しましょう。
ネストが深くなる場合は、以下の代替手段を検討しましょう。
代替1:関数に切り出す
JavaScript
function getGrade(score) {
if (score >= 90) return 'A';
if (score >= 80) return 'B';
if (score >= 70) return 'C';
if (score >= 60) return 'D';
return 'F';
}
const grade = getGrade(85); // "B"
代替2:オブジェクトマップで変換する
JavaScript
// 値が完全一致する場合はオブジェクトマップが最適
const statusLabels = {
pending: '保留中',
approved: '承認済み',
rejected: '却下',
cancelled: 'キャンセル',
};
// ネストした三項演算子の代わりにオブジェクトで検索
const label = statusLabels[status] ?? '不明';
ポイント:値が完全一致で決まるケースでは、オブジェクトマップを使うと三項演算子のネストもif-elseチェーンも不要になります。条件が増えてもオブジェクトにプロパティを追加するだけなので、メンテナンス性が高いのが特徴です。
短絡評価(&&, ||)との使い分け
三項演算子と似た役割を果たす短絡評価について理解し、適切に使い分けましょう。
&&(論理AND)による条件付き表示
&& は左辺がtruthyのときだけ右辺を返します。「条件を満たすときだけ何かを表示する」パターンに適しています。
JavaScript
// 三項演算子:偽の場合に空文字を返す
const warning = hasError ? 'エラーがあります' : '';
// && で同じことを書く(よりシンプル)
const warning = hasError && 'エラーがあります';
// Reactでの条件付きレンダリング
return (
<div>
{isLoading && <Spinner />}
{errorMessage && <Alert>{errorMessage}</Alert>}
</div>
);
注意:Reactで && を使うとき、左辺が 0 の場合は注意が必要です。0 && <Component /> は 0 を返すため、画面に 0 が表示されてしまいます。Boolean(count) && <Component /> または count > 0 && <Component /> と書くと安全です。
||(論理OR)によるデフォルト値
|| は左辺がfalsyのときに右辺を返します。デフォルト値の設定パターンに適しています。
JavaScript
// 三項演算子でデフォルト値
const name = userName ? userName : 'ゲスト';
// || で同じことを書く(よりシンプル)
const name = userName || 'ゲスト';
// ?? で書く(null/undefinedのみチェック)
const name = userName ?? 'ゲスト';
三項演算子・短絡評価・Null合体演算子の比較
| 演算子 |
構文 |
用途 |
判定基準 |
| 三項演算子 |
a ? b : c |
真偽で異なる値を返す |
truthy / falsy |
| && |
a && b |
条件を満たすときだけ値を返す |
truthy / falsy |
| || |
a || b |
falsy時にデフォルト値を返す |
truthy / falsy |
| ?? |
a ?? b |
null/undefined時にデフォルト値を返す |
null / undefined のみ |
使い分けの具体例
JavaScript
const user = {
name: '田中',
age: 0, // 0歳の赤ちゃん
nickname: '', // ニックネーム未設定(空文字)
email: null, // メール未登録
};
// 三項演算子:真偽で別々の値を返したいとき
const ageGroup = user.age >= 18 ? '成人' : '未成年';
// ||:falsyならデフォルト値(0や空文字もfalsyになる)
user.age || '未設定'; // "未設定"(0がfalsyなので)
user.nickname || '匿名'; // "匿名"(空文字がfalsyなので)
// ??:null/undefinedのみデフォルト値(0や空文字はそのまま)
user.age ?? '未設定'; // 0(nullでもundefinedでもない)
user.nickname ?? '匿名'; // ""(nullでもundefinedでもない)
user.email ?? '未登録'; // "未登録"(nullなので)
// &&:条件を満たすときだけ処理
user.email && sendEmail(user.email); // emailがnullなので実行されない
使い分けのコツ:「2つの値を出し分ける」なら三項演算子、「あるときだけ表示する」なら &&、「デフォルト値を設定する」なら || または ?? を使いましょう。0 や空文字を有効な値として扱いたい場合は ?? を選びます。
よくあるミスと注意点
三項演算子は便利ですが、使い方を誤るとバグや可読性の低下につながります。よくあるミスを確認しておきましょう。
ミス1:代入を忘れる(結果を捨ててしまう)
三項演算子は値を返す式です。返された値を使わないと、何も起きません。
JavaScript
const score = 75;
// NG: 結果をどこにも代入していない
score >= 60 ? '合格' : '不合格'; // 値が返されるが、捨てられる
// OK: 変数に代入する
const result = score >= 60 ? '合格' : '不合格';
// OK: 関数の引数として使う
console.log(score >= 60 ? '合格' : '不合格');
ミス2:副作用のある処理に使う
三項演算子の中で副作用(DOM操作、API呼び出し、変数の変更など)を行うのはアンチパターンです。
JavaScript
let count = 0;
// NG: 三項演算子の中で副作用を実行している
isValid ? count++ : console.error('invalid');
// OK: if-elseで書く(副作用があるなら文で書く)
if (isValid) {
count++;
} else {
console.error('invalid');
}
三項演算子は「値を選ぶ」ためのもの、if-elseは「処理を分岐する」ためのもの、と覚えておきましょう。副作用を伴う処理はif-elseで書くのが原則です。
ミス3:複雑な条件での可読性低下
条件式が長い場合、三項演算子を使うとかえって読みにくくなります。
JavaScript
// NG: 条件が長すぎて読みにくい
const msg = user.isAdmin && user.isActive && !user.isBanned && user.permissions.includes('edit')
? '編集可能'
: '閲覧のみ';
// OK: 条件を変数に切り出す
const canEdit = user.isAdmin
&& user.isActive
&& !user.isBanned
&& user.permissions.includes('edit');
const msg = canEdit ? '編集可能' : '閲覧のみ';
ポイント:条件が複雑な場合は、まず条件部分を意味のある名前の変数に切り出しましょう。三項演算子自体がシンプルになり、条件の意味も明確になります。
ミス4:演算子の優先順位の罠
三項演算子は他の演算子と組み合わせるとき、優先順位に注意が必要です。
JavaScript
// 文字列結合との組み合わせ
const isVIP = true;
// NG: + の方が ? より優先順位が高い
const text = 'ステータス: ' + isVIP ? 'VIP' : '一般';
// => "VIP"("ステータス: true" がtruthyなので "VIP" が返る)
// OK: 三項演算子を括弧で囲む
const text = 'ステータス: ' + (isVIP ? 'VIP' : '一般');
// => "ステータス: VIP"
// テンプレートリテラルなら括弧不要(${}が式を隔離するため)
const text = `ステータス: ${isVIP ? 'VIP' : '一般'}`;
// => "ステータス: VIP"
注意:三項演算子を + と組み合わせるときは、必ず括弧で囲みましょう。迷ったらテンプレートリテラルを使えば、この問題を自然に回避できます。
まとめ:三項演算子の使い分けフローチャート
最後に、三項演算子を使うべきかどうかの判断基準を整理します。
| 状況 |
推奨する書き方 |
理由 |
| 条件に応じて2つの値を出し分ける |
三項演算子 |
constで宣言でき、簡潔に書ける |
| 条件を満たすときだけ表示したい |
&& |
: '' が不要でシンプル |
| null/undefinedのデフォルト値を設定 |
?? |
0や空文字を有効値として扱える |
| falsyなら何でもデフォルト値にしたい |
|| |
最も簡潔な書き方 |
| 3つ以上の分岐がある |
if-else / 関数 / オブジェクトマップ |
ネストは可読性が低下する |
| 副作用のある処理を分岐する |
if-else |
三項演算子は値の選択専用 |
この記事のポイント
- 三項演算子は
条件 ? 真の値 : 偽の値 の構文で、値を返す式である
- if-elseは「文」、三項演算子は「式」。式が必要な場所(変数の右辺、引数、テンプレートリテラル、JSX)で活躍する
- 変数代入で三項演算子を使うと
let → const にできるケースが多い
- ネストは2段階までに抑え、それ以上は関数やオブジェクトマップで代替する
&&(条件付き表示)、||(falsyデフォルト)、??(null/undefinedデフォルト)と適切に使い分ける
- 三項演算子は「値を選ぶ」ためのもの。副作用のある処理にはif-elseを使う
三項演算子は正しく使えばコードを簡潔にし、const宣言を増やしてコードの安全性を高める強力なツールです。一方で、濫用すると可読性を損ないます。「シンプルな条件での値の出し分け」という本来の用途を意識して、適切に使い分けていきましょう。