この質問はコメントでほとんど回答されていますが、いくつかのコメントを拡張して、追加の洞察を提供したいと思いました.
Frédéric Hamidiがコメントで指摘したように、優れた JavaScript JIT コンパイラは、おそらくコードの両方のサンプルを修正し、まったく同じ結果を生成します。ただし、最適化を提供する JIT コンパイラーがなく、代わりに、コマンドを順次実行するインタープリターがあるとします。
その場合、最初の例 ( if-elseif-else を使用) では、次の手順が実行されます (大まかなアセンブリの疑似コードで申し訳ありませんが、問題を示していると思います)。
1. CMP a, 0 // compare value of a to zero
2. JZ 5 // If comparison is zero (a and 0 are equivalent), jump to the address of the else-if (starts on 5) instruction
3. CALL doSomething(a) // Not how you would pass a parameter in assembly, but we'll skip over that stuff as it is irrelevant
4. JMP 10 // Jump to end line. We do not need to do other evaluations.
5. CMP b, 0 // Compare value of b to zero
6. JZ 9 // If comparison is zero, jump to the else instruction (line 9)
7. CALL doSomething(b)
8. JMP 10 // Jump to end line. We do not need to do other evaluations.
9. doSomething(c) // Else, we do something to C
10. RET // Return/exit. We are finished.
一方、コードの 2 番目のサンプル (ブール演算のみを使用するサンプル) のシーケンスを見てみましょう。
1. CMP a, 0
2. JZ 6 // Start of comparison #2
3. CALL doSomething(a)
4. CMP EAX, 0 // Let's assume the call to doSomething puts a result in EAX
5. JNZ 23 // Jump to end if doSomething returned a "truthy" result. Line 23 is the function's return point
6. NOT a // let's say this call puts the NOTed a in EDX register
7. CMP EDX, 0
8. JZ 14 // start of comparison #3
9. CMP b, 0
10. JZ 14 // start of comparison #3
11. CALL doSomething(b)
12. CMP EAX, 0
13. JNZ 23 // Again, jumping to return if doSomething returned "truthy" value.
14. NOT a
15. CMP EDX, 0
16. JZ 23
17. NOT b
18. CMP EDX, 0
19. JZ 23
20. CALL doSomething(c)
21. CMP EAX, 0
23. RET
サンプル コード #1 (if-elseif-else
分岐を使用) の方が効率的である可能性が高いと言えます。繰り返しになりますが、質問のコメントで述べたように、優れた JIT コンパイラはおそらく両方のコード サンプルを同等の状態に最適化しますが、コードを最適化するためのコンパイラを使用せずにインタプリタのみを利用している場合は、2 番目のコードこの例では、チェックする条件と変数が増えるため、より多くの操作が必要になります。
注: ここでのアセンブリは決して 100% 正確ではなく、適切なアセンブリではなく実際には疑似コードです。各コードサンプルで実行する必要がある操作の数の違いを指摘するために、これを単に含めました。