[英]Does JavaScript have “Short-circuit” evaluation?
我想知道 JavaScript 是否有像 C# 中的 && 運算符這樣的“短路”評估。 如果沒有,我想知道是否有一種可行的解決方法可以采用。
這個答案非常詳細地介紹了 JavaScript 中的短路如何工作,以及所有問題和相關主題,例如運算符優先級,如果您正在尋找快速定義並且已經了解短路的工作原理,我會推薦檢查其他答案。
首先讓我們檢查一下我們都熟悉的行為,在if()
塊中,我們使用&&
來檢查這兩件事是否為true
:
if (true && true) {
console.log('bar');
}
現在,您的第一直覺可能會說: “啊,是的,很簡單,如果expr1
和expr2
都被評估為true
,代碼就會執行語句”
嗯,是和不是。 您在技術上是正確的,這就是您所描述的行為,但這並不是評估代碼的方式,我們需要深入研究才能完全理解。
&&
和||
究竟是怎樣的解釋?:是時候看看“ JavaScript引擎的底層”了。 讓我們考慮這個實際例子:
function sanitise(x) { if (isNaN(x)) { return NaN; } return x; } let userinput = 0xFF; // as an example const res = sanitise(userinput) && userinput + 5 console.log(res);
結果是260
.. 但為什么呢? 為了得到答案,我們需要了解短路評估是如何工作的。
由MDN定義的
&&
運營商在expr1 && expr2
是從動地執行:如果
expr1
可以轉換為true
,則返回expr2
; 否則,返回expr1
。
所以這意味着,在我們的實際示例中, const res
的評估方式如下:
expr1
- sanitise(0xFF)
0xFF
是 250 的有效十六進制數,否則我將返回NaN
expr1
返回一個“真實”值,是執行expr2
時間(否則我會停止,因為NaN
是假的)userinput
是truthy(數字),我可以添加+5
吧 所以在這里,我們能夠避免額外的if
塊,並使用&&
運算符的簡單用法進一步檢查isNaN
。
到現在為止,我們至少應該了解短路運算符的工作原理。 通用規則是:
(some falsy expression) && expr
將計算為假表達式(some truthy expression) || expr
(some truthy expression) || expr
將評估為真表達式以下是一些進一步的示例,以便更好地理解:
function a() { console.log('a'); return false; } function b() { console.log('b'); return true; } if ( a() && b() ){ console.log('foobar'); } //Evaluates a() as false, stops execution.
function a() { console.log('a'); return false; } function b() { console.log('b'); return true; } if ( a() || b() ){ console.log('foobar'); } /* 1. Evaluates a() as false 2. So it should execute expr2, which is `b()` 3. b() returned as true, executing statement `console.log('foobar');` */
很好,希望你能掌握它! 我們需要知道的最后一件事是關於運算符優先級的規則,即:
&&
運算符總是在||
之前執行操作員。考慮以下示例:
function a() { console.log('a'); return true;} function b() { console.log('b'); return false;} function c() { console.log('c'); return false;} console.log(a() || b() && c()); // returns a() and stops execution
這將作為a()
返回,可能會令人困惑。 原因很簡單,只是我們的視力在欺騙我們,因為我們習慣於從左到右閱讀。 讓我們把console.log()
和什么不出來,完全專注於評估
true || false && false
現在讓你的頭腦圍繞這個:
我們說&&
運算符具有優先級,因此它被評估為第一個。 為了幫助我們更好地想象評估,想想定義
expr1 && expr2
在哪里:
expr2
是false
expr1
為true || false
true || false
所以這是棘手的部分,現在是true || false
true || false
被評估( expr1
- &&
左側)。
||
運算符在expr1 || expr2
停止執行 expr1 || expr2
在expr1
計算結果為truthy,所述expr1
被執行,代碼執行停止。 返回值為true
嗯..這很棘手,因為很少有奇怪的規則和語義。 但請記住,您始終可以使用()
來逃避運算符優先級 -就像在數學中一樣
function a() { console.log('a'); return true;} function b() { console.log('b'); return false;} function c() { console.log('c'); return false;} console.log((a() || b()) && c()); /* 1. The () escape && operator precedence 2. a() is evaluated as false, so expr2 (c()) to be executed 3. c() */
這個想法是從左到右讀取邏輯表達式,如果左條件的值足以得到總值,則不會處理和評估右條件。 一些非常簡單的例子:
function test() { const caseNumber = document.querySelector('#sel').value; const userChoice = () => confirm('Press OK or Cancel'); if (caseNumber === '1') { console.log (1 === 1 || userChoice()); } else if (caseNumber === '2') { console.log (1 === 2 && userChoice()); } else if (caseNumber === '3') { console.log (1 === 2 || userChoice()); } else if (caseNumber === '4') { console.log (1 === 1 && userChoice()); } else if (caseNumber === '5') { console.log (userChoice() || 1 === 1); } else if (caseNumber === '6') { console.log (userChoice() && 1 === 2); } }
<label for="sel">Select a number of a test case and press "RUN!":</label> <br><select id="sel"> <option value="">Unselected</option> <option value="1">Case 1</option> <option value="2">Case 2</option> <option value="3">Case 3</option> <option value="4">Case 4</option> <option value="5">Case 5</option> <option value="6">Case 6</option> </select> <button onclick="test()">RUN!</button>
上面的前兩種情況將分別打印到控制台結果true
和false
,您甚至不會看到要求您按“確定”或“取消”的模式窗口,因為左側條件足以定義總結果。 相反,在情況 3-6 中,您將看到模態窗口要求您選擇,因為前兩者取決於正確的部分(即您的選擇),而后兩者 - 無論聚合這些表達式的值不取決於您的選擇——因為首先讀取左條件。 因此,根據要首先處理的條件從左到右放置條件非常重要。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.