演算子と式 — 等価比較・短絡評価・オプショナルチェーン
JavaScriptの演算子には、他の言語とは少し違う挙動をするものがいくつかあります。
特に == と ===、そして && や || を使った短絡評価は、実務コードで頻繁に登場するにもかかわらず、誤解されがちなポイントです。
この章では「なぜそう動くのか」を理解することで、コードを書くときに迷わなくなることを目指します。
学習者== と ===、結局どっちを使えばいいの?最近見る ?? や ?. も何者…?
等価比較:== と === の違い
JavaScriptには等価演算子が2種類あります。
console.log(1 == '1'); // true
console.log(1 === '1'); // false==(抽象的等価比較)
== は比較の前に**型強制(Type Coercion)**を行います。
型が違う場合、JavaScriptが自動的に片方の型を変換してから比較します。
console.log(0 == false); // true — false が 0 に変換される
console.log('' == false); // true — どちらも 0 に変換される
console.log(null == undefined); // true — 特別ルール
console.log(null == 0); // false — null は null/undefined としか == で true にならない
console.log([] == false); // true — [] → '' → 0、false → 0型強制のルールは複雑で、人間の直感に反する結果になることが多いです。
===(厳格等価比較)
=== は型強制を行わず、型も値も完全に一致する場合のみ true を返します。
console.log(1 === 1); // true
console.log(1 === '1'); // false — 型が違う
console.log(null === null); // true
console.log(null === undefined); // false — 型が違う== の比較フローを図で整理します。
実務では == を使う理由はほぼなく、常に === を使うのがベストプラクティスです。唯一の例外は null チェックで、null == undefined が true になる性質を意図的に使うケースがあります。
// null と undefined のどちらも弾きたい場合のみ == を使う例外的なパターン
if (value == null) {
// value が null または undefined のときに入る
}
// 上と同じ意味(こちらの方が明示的)
if (value === null || value === undefined) {
// ...
}論理演算子と短絡評価
&&(AND)と ||(OR)は単なる真偽値チェックではなく、値をそのまま返すという重要な性質があります。
&&:左辺が falsy なら左辺を、truthy なら右辺を返す
console.log(0 && 'hello'); // 0 — 左辺が falsy なので左辺を返す
console.log(1 && 'hello'); // 'hello' — 左辺が truthy なので右辺を返す
console.log('' && 'hello'); // '' — 左辺が falsy
console.log('foo' && 'bar'); // 'bar' — 左辺が truthy なので右辺を返す右辺まで評価しないことを**短絡評価(short-circuit evaluation)**と呼びます。
左辺が false と確定した時点で、右辺は実行されません。
// 右辺の関数はログが false のとき実行されない
const isLoggedIn = false;
isLoggedIn && console.log('ようこそ'); // 何も出力されない
// React でよく見るパターン:条件付きレンダリング
function UserGreeting({ user }) {
return <div>{user && <span>こんにちは、{user.name}さん</span>}</div>;
}||:左辺が falsy なら右辺を、truthy なら左辺を返す
console.log(0 || 'デフォルト'); // 'デフォルト' — 左辺が falsy
console.log('hello' || 'デフォルト'); // 'hello' — 左辺が truthy
console.log(null || 'フォールバック'); // 'フォールバック'デフォルト値のフォールバックパターンとしてよく使われます。
function greet(name) {
const displayName = name || '名無し';
return `こんにちは、${displayName}さん`;
}
greet('Alice'); // "こんにちは、Aliceさん"
greet(''); // "こんにちは、名無しさん" — 空文字は falsy
greet(null); // "こんにちは、名無しさん"
Nullish Coalescing:??
|| のデフォルト値パターンには落とし穴があります。0 や '' も falsy として扱われるため、意図しないフォールバックが起きることがあります。
const config = {
timeout: 0, // タイムアウトなし(意図的な 0)
label: '', // 空ラベル(意図的な空文字)
};
// || を使うと意図しない結果に
const timeout = config.timeout || 5000; // 5000 になってしまう(0 は falsy)
const label = config.label || '未設定'; // '未設定' になってしまう??(Nullish Coalescing)は null または undefined のときだけフォールバックし、0 や '' はfalsy でもそのまま左辺を返す演算子です。
console.log(0 ?? 'デフォルト'); // 0 — 0 は nullish ではない
console.log('' ?? 'デフォルト'); // '' — '' は nullish ではない
console.log(null ?? 'デフォルト'); // 'デフォルト'
console.log(undefined ?? 'デフォルト'); // 'デフォルト'先ほどの例を ?? で書き直すと意図通りになります。
const timeout = config.timeout ?? 5000; // 0 のまま
const label = config.label ?? '未設定'; // '' のままオプショナルチェーン:?.
ネストされたオブジェクトのプロパティにアクセスするとき、途中が null や undefined だとエラーになります。
const user = null;
console.log(user.profile.name);
// TypeError: Cannot read properties of null (reading 'profile')従来は && を使って防御的に書く必要がありました。
const name = user && user.profile && user.profile.name;
// 冗長で読みにくい?.(オプショナルチェーン)を使うと、途中が null または undefined の場合にエラーを投げず undefined を返すようになります。
const user = null;
console.log(user?.profile?.name); // undefined(エラーにならない)
const user2 = { profile: { name: 'Alice' } };
console.log(user2?.profile?.name); // 'Alice'メソッド呼び出しにも使える
const callback = null;
callback?.(); // エラーにならず undefined を返す
const arr = null;
arr?.map((x) => x * 2); // undefined(エラーにならない)ブラケット記法にも使える
const data = null;
console.log(data?.['key']); // undefined?? との組み合わせ
?. で undefined が返ってきた場合のフォールバックに ?? を組み合わせるパターンは非常によく使われます。
const user = { profile: null };
const name = user?.profile?.name ?? '名前未設定';
const country = user?.address?.country ?? '国籍不明';
console.log(name); // '名前未設定'
console.log(country); // '国籍不明'
論理代入演算子
ES2021 で追加された演算子です。論理演算と代入を組み合わせた省略記法です。
// &&= : 左辺が truthy のときだけ右辺を代入
let a = 1;
a &&= 10; // a は truthy なので 10 が代入される → 10
let b = 0;
b &&= 10; // b は falsy なので代入されない → 0
// ||= : 左辺が falsy のときだけ右辺を代入
let c = null;
c ||= 'デフォルト'; // c は falsy なので代入される → 'デフォルト'
let d = 'hello';
d ||= 'デフォルト'; // d は truthy なので代入されない → 'hello'
// ??= : 左辺が null/undefined のときだけ右辺を代入
let e = 0;
e ??= 99; // 0 は nullish ではないので代入されない → 0
let f = null;
f ??= 99; // null なので代入される → 99演算子の優先順位と括弧
&& は || より優先順位が高いです。
// && が先に評価される
true ||
(false &&
false(
// → true || (false && false)
// → true || false
// → true
// 意図を明確にするなら括弧を使う
true || false,
) &&
false); // → false?? は && や || と混在させることができません(優先順位が曖昧なため、構文エラーになります)。
// エラー
null || undefined ?? 'デフォルト'; // SyntaxError
// 括弧で明示する
(null || undefined) ?? 'デフォルト'; // 'デフォルト'
null || (undefined ?? 'デフォルト'); // 'デフォルト'よくある疑問
falsy な値はどれ?
JavaScriptで「偽として扱われる」値(falsy)は6種類だけです。
| 値 | 型 | 備考 |
|---|---|---|
false | boolean | 真偽値の false |
0 | number | ゼロ(-0 と 0n も含む) |
'' | string | 空文字列 |
null | null | 値がないことを明示 |
undefined | undefined | 未定義 |
NaN | number | 非数 |
それ以外はすべて truthy です。[](空配列)や {}(空オブジェクト)も truthy です。
console.log([] == false); // true — == の型強制で変換されるから
if ([]) {
console.log('空配列は truthy'); // こちらが実行される
}
NaN の比較
NaN は自分自身とも等しくないという特殊な値です。
console.log(NaN === NaN); // false — NaN は自分自身とも一致しない
console.log(NaN == NaN); // false
// 正しいチェック方法
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN(undefined)); // false(isNaN() と挙動が異なる)まとめ
| 演算子 | 用途 | 注意点 |
|---|---|---|
=== | 等価比較(推奨) | 型も値も比較 |
== | 基本使わない | 型強制が発生 |
&& | 条件付き実行・レンダリング | 左辺が 0 のとき 0 が返る |
|| | falsy フォールバック | 0 や '' も上書きされる |
?? | null/undefined フォールバック | 0 や '' は上書きされない |
?. | ネストした null セーフアクセス | 過度な使用は null を隠す |
??= | null/undefined のときだけ代入 | キャッシュ初期化などに便利 |

次の章では制御構文(if・switch・ループ)の実務パターンを見ていきます。