if (user.age >= 18 && user.country === "JP" && !user.isBanned) のような条件式は、1行で書けますが読み解くのに時間がかかります。
このような複雑な条件を意味のある変数名に分解することで、コードを「仕様書のように読める」状態に変えられます。この記事では、条件判定に変数を活用して可読性・保守性を高める実践テクニックを解説します。
複雑な条件式を変数に切り出して読みやすくする
条件をそのまま if 文に書くより、意図を表した変数名に代入してから使うと、コードを読んだだけで「何をチェックしているか」が分かります。
// 何をチェックしているか読み解くのに時間がかかる
if (user.age >= 18 && user.country === 'JP' && !user.isBanned && user.role !== 'guest') {
showPremiumContent();
}
const isAdult = user.age >= 18;
const isDomestic = user.country === 'JP';
const isActiveUser = !user.isBanned;
const isLoggedIn = user.role !== 'guest';
const canViewPremium = isAdult && isDomestic && isActiveUser && isLoggedIn;
if (canViewPremium) {
showPremiumContent();
}
is〜・has〜・can〜・should〜 で始まる名前にすると、変数が boolean であることが一目でわかります。isAdult・hasPermission・canEdit・shouldRefresh のような形が理想です。条件変数が特に効果的な3つのパターン
パターン①:何度も使う条件を1つにまとめる
const isAdmin = user.role === 'admin' || user.role === 'superadmin'; // 1つの変数を複数箇所で使い回せる if (isAdmin) showAdminMenu(); if (isAdmin) allowDataExport(); if (isAdmin) enableUserManagement(); // NG: 条件をその都度書くと変更漏れのリスクがある // if (user.role === 'admin' || user.role === 'superadmin') showAdminMenu(); // if (user.role === 'admin' || user.role === 'superadmin') allowDataExport(); ...
パターン②:条件の意味をビジネスロジックで表現する
// 技術的な条件をそのまま書くと、後から読んだときに意図が不明瞭
if (items.length > 0 && totalPrice >= 3000 && couponCode !== null && !isHoliday) {
applyFreeShipping();
}
// 各条件をビジネス用語で命名して意図を明確化
const hasItems = items.length > 0;
const meetsMinOrder = totalPrice >= 3000; // 3000円以上で送料無料
const hasCoupon = couponCode !== null;
const isEligibleDay = !isHoliday; // 祝日は対象外
const qualifiesForFreeShipping = hasItems && meetsMinOrder && (hasCoupon || isEligibleDay);
if (qualifiesForFreeShipping) {
applyFreeShipping();
}
パターン③:段階的な条件チェック(フェーズ分け)
// 段階ごとに変数を作ることで、どの段階で失敗したかも追いやすい
const isFormValid = form.checkValidity();
const isNetworkOk = navigator.onLine;
const isNotSubmitting = !isSubmitting;
// 全条件が揃ったときだけ送信可能
const canSubmit = isFormValid && isNetworkOk && isNotSubmitting;
submitBtn.disabled = !canSubmit;
// どの条件が失敗しているか個別に確認できる
if (!isFormValid) showError('入力内容を確認してください');
if (!isNetworkOk) showError('オフライン状態です');
if (!isNotSubmitting) showError('送信中です。しばらくお待ちください');
早期リターン(ガード節)で条件のネストを減らす
複数の条件チェックを if/else のネストで書くと深くなりがちです。ガード節(Guard Clause)で無効な状態を先に弾くと、メインロジックがフラットで読みやすくなります。
function processOrder(order) {
if (order) {
if (order.items.length > 0) {
if (order.user.isVerified) {
if (!order.isCancelled) {
// ようやくメインロジック
chargePayment(order);
sendConfirmationEmail(order);
}
}
}
}
}
function processOrder(order) {
// 無効な状態を先に弾く(ガード節)
if (!order) return;
if (order.items.length === 0) return;
if (!order.user.isVerified) return;
if (order.isCancelled) return;
// メインロジックはフラットに書ける
chargePayment(order);
sendConfirmationEmail(order);
}
function processOrder(order) {
const isValidOrder = order && order.items.length > 0;
const isUserVerified = order?.user?.isVerified;
const isNotCancelled = !order?.isCancelled;
if (!isValidOrder) return;
if (!isUserVerified) return;
if (!isNotCancelled) return;
chargePayment(order);
sendConfirmationEmail(order);
}
状態を定数変数で管理する(Enum 的パターン)
「”active”・”inactive”・”pending” のような文字列をハードコードしない」ことが保守性の基本です。定数オブジェクトで状態を管理すると、タイポによるバグを防ぎ IDE の補完も効くようになります。
// 'active' をあちこちで書くと typo が起きやすい
if (user.status === 'actve') { // typo!バグになる
showDashboard();
}
// 状態を定数にまとめる(Object.freeze で変更を防ぐ)
const USER_STATUS = Object.freeze({
ACTIVE: 'active',
INACTIVE: 'inactive',
PENDING: 'pending',
BANNED: 'banned',
});
// 使うときは定数経由(タイポしても JS がエラーを出す)
if (user.status === USER_STATUS.ACTIVE) {
showDashboard();
}
// 複数状態の一括チェック
const VIEWABLE_STATUSES = [USER_STATUS.ACTIVE, USER_STATUS.PENDING];
const canView = VIEWABLE_STATUSES.includes(user.status);
if (canView) showContent();
type UserStatus = "active" | "inactive" | "pending" のような Union 型やenum UserStatus { Active = "active", ... } で型安全にできます。純粋な JavaScript では上記の Object.freeze() パターンが最も近い代替です。switch 文の代替:オブジェクトマップパターン
値によって処理を分岐するとき、switch 文の代わりにオブジェクト(マップ)を使うとよりコンパクトに書けます。
// switch 文(長くなりやすい)
function getStatusLabel(status) {
switch (status) {
case 'active': return '有効';
case 'inactive': return '無効';
case 'pending': return '審査中';
case 'banned': return '凍結';
default: return '不明';
}
}
// オブジェクトマップ(コンパクト)
const STATUS_LABELS = {
active: '有効',
inactive: '無効',
pending: '審査中',
banned: '凍結',
};
function getStatusLabel(status) {
return STATUS_LABELS[status] ?? '不明';
}
// 処理(関数)もマップできる
const ACTIONS = {
'click': () => console.log('クリックされました'),
'hover': () => console.log('ホバーされました'),
'submit': () => console.log('送信されました'),
};
function handleEvent(type) {
const action = ACTIONS[type];
if (action) action();
}
条件変数はデバッグも容易にする
条件を変数に切り出すと、console.log でそれぞれの状態を確認しやすくなります。
const isAdult = user.age >= 18;
const isDomestic = user.country === 'JP';
const isActiveUser = !user.isBanned;
// 各条件を個別に確認できる
console.log({ isAdult, isDomestic, isActiveUser });
// { isAdult: true, isDomestic: false, isActiveUser: true }
// → isDomestic が false なのが原因とすぐわかる
const canViewPremium = isAdult && isDomestic && isActiveUser;
console.log('canViewPremium:', canViewPremium); // false
console.log("isAdult:", isAdult) より console.log({ isAdult }) のほうが変数名が自動的に表示されて便利です。よくある質問
if (isActive) など)は変数化する必要はありません。目安として、条件式が2つ以上の論理演算子を含む場合や、同じ条件を複数箇所で使う場合に変数化を検討してください。「変数名を読めば何をチェックしているか即座にわかる」ことが変数化の判断基準です。const が適切です。let を使うと「後から変更するかもしれない」という誤ったシグナルを送ることになります。再代入が必要な場合(フラグを途中で変更するなど)のみ let を使ってください。Object.freeze() なしでは USER_STATUS.ACTIVE = "changed" のような変更が可能です。Object.freeze() を使うと以降の変更は無視(またはエラー)されます。TypeScript では const STATUS = { ... } as const で読み取り専用にできます。function canView(isLoggedIn, isVerified, hasPermission) のように引数名で条件を明示することで、呼び出し側のコードも読みやすくなります。まとめ
条件判定に変数を活用するポイントをまとめます。
- 複雑な条件式は
is〜/has〜/can〜で始まる意味のある変数名に分解する - 同じ条件を複数箇所で使うなら変数化してDRY(重複排除)を実現する
- ガード節(早期リターン)でネストを浅くし、メインロジックをフラットに保つ
- 状態値(”active” など)は
Object.freeze()で定数化してタイポを防ぐ switch文はオブジェクトマップで置き換えるとコンパクトになる- 条件変数は
console.log({ isAdult, isDomestic })で個別デバッグがしやすくなる
if 文の詳しい使い方は【JavaScript】if 文による条件分岐の書き方、switch 文の使い方は【JavaScript】switch 文の使い方もあわせてご覧ください。
