三項演算子 (? :) と論理AND演算子 (&&) 、どっち使った方がいいの?
JSX内では、三項演算子(? :)と論理AND演算子(&&)を条件付きレンダリングとして利用することが出来ます。
先日、自分のPRに「三項演算子を使うより論理AND演算子を使った方がいいよ」ってレビューをいただきました。
今回は、実際にどちらの評価の負荷が大きいのか、どちらを使うべきなのかを調べてみようと思います。
テスト方法
テストを行うため、JavaScript の performance.now() を使って、処理時間を計測しました。1,000,000 回の繰り返しを行い、実行時間を比較します。
最初の評価テスト
テストコード
最初に、JSX内でよく使うこれらの演算子を使った場合のパフォーマンステストを実施しました。
実行したコードは以下です。
const { performance } = require('perf_hooks');
const iterations = 1_000_000; // 100万回実行
function benchmark(label, fn) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn();
}
const end = performance.now();
console.log(`${label}: ${(end - start).toFixed(3)} ms`);
}
const isHoge = true; // true の場合で比較
benchmark("Ternary ( ? : )", () => {
const result = isHoge ? 'hoge' : null;
});
benchmark("Logical AND (&&)", () => {
const result = isHoge && 'hoge';
});
テスト結果
Ternary ( ? : ): 14.667 ms //三項演算子(? :) → 約 1.66 ms
Logical AND (&&): 5.400 ms //論理AND演算子(&&) → 約 5.07 ms
意外な結果でした。&& の方が速いと思っていましたが、三項演算子 (? :) の方が約3倍速いという結果になっています。
「試してみた結果、論理AND演算子の方がやっぱり 速かったですね!大人しく&&使っときましょう!」ってオチにして終了で良いか、とか思ってたのに目論見が外れてしまいました。焦ってます。
もう少しテストを続けてみます。
追加の評価テスト
テストコード
const { performance } = require('perf_hooks');
const iterations = 1_000_000; // 100万回実行
function benchmark(label, fn) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn();
}
const end = performance.now();
console.log(`${label}: ${(end - start).toFixed(3)} ms`);
}
// isHoge = true の場合
console.log("=== isHoge = true ===");
let isHoge = true;
benchmark("Ternary ( ? : )", () => {
const result = isHoge ? 'hoge' : null;
});
benchmark("Logical AND (&&)", () => {
const result = isHoge && 'hoge';
});
// isHoge = false の場合
console.log("\n=== isHoge = false ===");
isHoge = false;
benchmark("Ternary ( ? : )", () => {
const result = isHoge ? 'hoge' : null;
});
benchmark("Logical AND (&&)", () => {
const result = isHoge && 'hoge';
});
// undefined を返す場合
console.log("\n=== Returning undefined instead of null ===");
isHoge = true;
benchmark("Ternary ( ? : ) with undefined", () => {
const result = isHoge ? 'hoge' : undefined;
});
benchmark("Logical AND (&&) with undefined", () => {
const result = isHoge && 'hoge';
});
ふたつの評価テストを追加しています。
// isHoge = false の場合
console.log("\n=== isHoge = false ===");
isHoge = false;
benchmark("Ternary ( ? : )", () => {
const result = isHoge ? 'hoge' : null;
});
benchmark("Logical AND (&&)", () => {
const result = isHoge && 'hoge';
});
評価フラグが false
の場合のテストを行なっています。
三項演算子では、評価フラグがfalseの場合に左辺の値(今回はnull)を返しますが、論理AND演算子では即終了します。ここで動作に差が生じるかを見てみます。
// undefined を返す場合
console.log("\n=== Returning undefined instead of null ===");
isHoge = true;
benchmark("Ternary ( ? : ) with undefined", () => {
const result = isHoge ? 'hoge' : undefined;
});
benchmark("Logical AND (&&) with undefined", () => {
const result = isHoge && 'hoge';
});
これは単純にnullじゃなくてundefinedにしたらどうなるかなっていう興味で追加したやつです。
テスト結果
=== isHoge = true ===
Ternary ( ? : ): 15.094 ms
Logical AND (&&): 9.214 ms
=== isHoge = false ===
Ternary ( ? : ): 4.030 ms
Logical AND (&&): 4.078 ms
=== Returning undefined instead of null ===
Ternary ( ? : ) with undefined: 4.240 ms
Logical AND (&&) with undefined: 4.190 ms
isHoge = true
の場合: 三項演算子(? :)が 15.09 ms で、論理AND演算子(&&)は 9.21 ms。三項演算子の方が遅かった。
isHoge = false の場合: 両者の差はほぼなし。三項演算子(? :)は 4.03 ms、論理AND(&&)は 4.08 ms。
undefined を返す場合: ほぼ同じ結果。三項演算子(? :)が 4.24 ms、論理AND(&&)は 4.19 ms。
結論
isHoge = true の時は、三項演算子が少し遅く、&& の方が高速。
他のケースでは、パフォーマンス差はほぼなし。
結果的に、パフォーマンス差は微小だけど、isHoge = true の時は && がやや優れていることが分かりました。
そもそも可読性という意味では、表示しないと割り切り 右辺をnullとするよりも、&&を使う方が良さそうですね。
追記
ブラウザのConsoleでも試してみました。
実行したコード
const iterations = 1_000_000; // 100万回実行
function benchmark(label, fn) {
console.time(label);
for (let i = 0; i < iterations; i++) {
fn();
}
console.timeEnd(label);
}
// isHoge = true の場合
console.log("=== isHoge = true ===");
let isHoge = true;
benchmark("Ternary ( ? : )", () => {
const result = isHoge ? 'hoge' : null;
});
benchmark("Logical AND (&&)", () => {
const result = isHoge && 'hoge';
});
// isHoge = false の場合
console.log("\n=== isHoge = false ===");
isHoge = false;
benchmark("Ternary ( ? : )", () => {
const result = isHoge ? 'hoge' : null;
});
benchmark("Logical AND (&&)", () => {
const result = isHoge && 'hoge';
});
// undefined を返す場合
console.log("\n=== Returning undefined instead of null ===");
isHoge = true;
benchmark("Ternary ( ? : ) with undefined", () => {
const result = isHoge ? 'hoge' : undefined;
});
benchmark("Logical AND (&&) with undefined", () => {
const result = isHoge && 'hoge';
});
結果
=== isHoge = true ===
Ternary ( ? : ): 3.139892578125 ms
Logical AND (&&): 11.06982421875 ms
=== isHoge = false ===
Ternary ( ? : ): 8.148193359375 ms
Logical AND (&&): 6.942138671875 ms
=== Returning undefined instead of null ===
Ternary ( ? : ) with undefined: 6.281982421875 ms
Logical AND (&&) with undefined: 5.85791015625 ms

株式会社SKIYAKIのテックブログです。ファンクラブプラットフォームBitfanの開発・運用にまつわる知見や調べたことなどを発信します。主な技術スタックは Ruby on Rails / React / AWS / Swift / Kotlin などです。 recruit.skiyaki.com/
Discussion