現代 JavaScript 教程 — 邏輯運算符

邏輯運算符

JavaScript 裏有三個邏輯運算符:||(或),&&(與),!(非)。javascript

雖然他們被稱爲「邏輯」運算符,但這些運算符卻能夠被應用於任意類型的值,而不只僅是布爾值。他們的結果也一樣能夠是任意類型。html

讓咱們來詳細看一下。java

||(或)

兩個豎線符號表示了「或」運算:react

result = a || b;
複製代碼

在傳統的編程中,邏輯或僅可以操做布爾值。若是參與運算的任意一個參數爲 true,返回的結果就爲 true,不然返回 false算法

在 JavaScript 中,邏輯運算符更加靈活強大。可是首先咱們看一下操做數是布爾值的時候發生了什麼。編程

下面是四種可能的邏輯組合:微信

alert( true || true );   // true
alert( false || true );  // true
alert( true || false );  // true
alert( false || false ); // false
複製代碼

正如咱們所見,除了兩個操做數都是 false 的狀況,結果都是 trueide

若是操做數不是布爾值,那麼它將會被轉化爲布爾值來參與運算。函數

例如,數字 1 將會被做爲 true,數字 0 則做爲 false學習

if (1 || 0) { // 工做原理至關於 if( true || false )
  alert( 'truthy!' );
}
複製代碼

大多數狀況,邏輯或 || 會被用在 if 語句中,用來測試是否有 任何 給定的條件爲 true

例如:

let hour = 9;

if (hour < 10 || hour > 18) {
  alert( 'The office is closed.' );
}
複製代碼

咱們能夠傳入更多的條件:

let hour = 12;
let isWeekend = true;

if (hour < 10 || hour > 18 || isWeekend) {
  alert( 'The office is closed.' ); // 是週末
}
複製代碼

或運算尋找第一個真值

上文提到的邏輯處理多少有些傳統了。下面讓咱們看看 JavaScript 的「附加」特性。

拓展的算法以下所示。

給定多個參與或運算的值:

result = value1 || value2 || value3;
複製代碼

或運算符 || 作了以下的事情:

  • 從左到右依次計算操做數。
  • 處理每個操做數時,都將其轉化爲布爾值。若是結果是 true,就中止計算,返回這個操做數的初始值。
  • 若是全部的操做數都被計算過(也就是,轉換結果都是 false),則返回最後一個操做數。

返回的值是操做數的初始形式,不會作布爾轉換。

也就是,一個或 "||" 運算的鏈,將返回第一個真值,若是不存在真值,就返回該鏈的最後一個值。

例如:

alert( 1 || 0 ); // 1(1 是真值)
alert( true || 'no matter what' ); //(true 是真值)

alert( null || 1 ); // 1(1 是第一個真值)
alert( null || 0 || 1 ); // 1(第一個真值)
alert( undefined || null || 0 ); // 0(全部的轉化結果都是 false,返回最後一個值)
複製代碼

與「純粹的、傳統的、僅僅處理布爾值的或運算」相比,這個規則就引發了一些頗有趣的用法。

  1. 獲取變量列表或者表達式的第一個真值。

    假設咱們有幾個變量,它們可能包含某些數據或者是 null/undefined。咱們須要選出第一個包含數據的變量。

    咱們能夠這樣應用或運算 ||

    let currentUser = null;
    let defaultUser = "John";
    
    let name = currentUser || defaultUser || "unnamed";
    
    alert( name ); // 選出了 「John」 — 第一個真值
    複製代碼

    若是 currentUserdefaultUser 都是假值,那麼結果就是 "unnamed"

  2. 短路取值。

    操做數不只僅能夠是值,還能夠是任意表達式。或運算會從左到右計算並測試每一個操做數。當找到第一個真值,計算就會中止,並返回這個值。這個過程就叫作「短路取值」,由於它儘量地減小從左到右計算的次數。

    當表達式做爲第二個參數而且有必定的反作用(side effects),好比變量賦值的時候,短路取值的狀況就清楚可見。

    若是咱們運行下面的例子,x 將不會被賦值:

    let x;
    
    true || (x = 1);
    
    alert(x); // undefined,由於 (x = 1) 沒有被執行
    複製代碼

    若是第一個參數是 false,或運算將會繼續,並計算第二個參數,也就會運行賦值操做。

    let x;
    
    false || (x = 1);
    
    alert(x); // 1
    複製代碼

    賦值操做只是一個很簡單的狀況。可能有反作用,若是計算沒有到達,反作用就不會發生。

    正如咱們所見,這種用法是「if 語句的簡短方式」。第一個操做數被轉化爲布爾值,若是是假,那麼第二個參數就會被執行。

    大多數狀況下,最好使用常規的 if 語句,這樣代碼可讀性更高,可是有時候這種方式會很簡潔。

&&(與)

兩個 & 符號表示 && 與操做:

result = a && b;
複製代碼

傳統的編程中,當兩個操做數都是真值,與操做返回 true,不然返回 false

alert( true && true );   // true
alert( false && true );  // false
alert( true && false );  // false
alert( false && false ); // false
複製代碼

使用 if 語句的例子:

let hour = 12;
let minute = 30;

if (hour == 12 && minute == 30) {
  alert( 'Time is 12:30' );
}
複製代碼

就像或運算同樣,與運算的操做數能夠是任意類型的值:

if (1 && 0) { // 做爲 true && false 來執行
  alert( "won't work, because the result is falsy" );
}
複製代碼

與操做尋找第一個假值

給出多個參加與運算的值:

result = value1 && value2 && value3;
複製代碼

與運算 && 作了以下的事:

  • 從左到右依次計算操做數。
  • 將處理每個操做數時,都將其轉化爲布爾值。若是結果是 false,就中止計算,並返回這個操做數的初始值。
  • 若是全部的操做數都被計算過(也就是,轉換結果都是 true),則返回最後一個操做數。

換句話說,與操做符返回第一個假值,若是沒有假值就返回最後一個值。

上面的規則和或運算很像。區別就是與運算返回第一個假值而或操做返回第一個真值。

例如:

// 若是第一個操做符是真值,
// 與操做返回第二個操做數:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5

// 若是第一個操做符是假值,
// 與操做直接返回它。第二個操做數被忽略
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
複製代碼

咱們也能夠在一行代碼上串聯多個值。查看第一個假值是否被返回:

alert( 1 && 2 && null && 3 ); // null
複製代碼

若是全部的值都是真值,最後一個值將會被返回:

alert( 1 && 2 && 3 ); // 3,最後一個值
複製代碼

與運算 && 在或操做符 || 以前執行

與運算 && 的優先級比或運算 || 要高。

因此代碼 a && b || c && d 徹底跟 && 表達式加了括號同樣:(a && b) || (c && d)

就像或運算同樣,與運算 && 有時候可以代替 if

例如:

let x = 1;

(x > 0) && alert( 'Greater than zero!' );
複製代碼

&& 右邊的代碼只有運算抵達到那裏才能被執行。也就是,當且僅當 (x > 0) 返回了真值。

因此咱們基本能夠相似地獲得:

let x = 1;

if (x > 0) {
  alert( 'Greater than zero!' );
}
複製代碼

&& 的代碼變體看上去更短。可是 if 的含義更明顯,可讀性也更高。

因此建議是根據目的選擇代碼的結構。須要條件判斷就用 if,須要與運算就用 &&

!(非)

感嘆符號 ! 表示布爾非運算。

語法至關簡單:

result = !value;
複製代碼

操做符接受一個參數,並按以下運做:

  1. 將操做數轉化爲布爾類型:true/false
  2. 返回相反的值。

例如:

alert( !true ); // false
alert( !0 ); // true
複製代碼

兩個非運算 !! 有時候用來將某個值轉化爲布爾類型:

alert( !!"non-empty string" ); // true
alert( !!null ); // false
複製代碼

也就是,第一個非運算將該值轉化爲布爾類型並取反,第二個非運算再次取反。最後咱們就獲得了一個任意值到布爾值的轉化。

有更多詳細的方法能夠完成一樣的事 —— 一個內置的 Boolean 函數:

alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
複製代碼

非運算符 ! 的優先級在全部邏輯運算符裏面最高,因此它老是在 &&|| 前執行。

做業題

先本身作題目再看答案。

1. 或運算的結果是什麼?

重要程度:⭐️⭐️⭐️⭐️⭐️

以下代碼將會輸出什麼?

alert( null || 2 || undefined );
複製代碼

2. 或運算和 alerts 的結果是什麼?

重要程度:⭐️⭐️⭐

下面的代碼將會輸出什麼?

alert( alert(1) || 2 || alert(3) );
複製代碼

3. 與操做的結果是什麼?

重要程度:⭐️⭐️⭐️⭐️⭐️

下面這段代碼將會顯示什麼?

alert( 1 && null && 2 );
複製代碼

4. 與運算鏈接的 alerts 的結果是什麼?

重要程度:⭐️⭐️⭐

這段代碼將會顯示什麼?

alert( alert(1) && alert(2) );
複製代碼

5. 或運算、與運算、或運算串聯的結果

重要程度:⭐️⭐️⭐️⭐️⭐️

結果將會是什麼?

alert( null || 2 && 3 || 4 );
複製代碼

6. 檢查值是否位於範圍區間內

重要程度:⭐️⭐️⭐

寫一個「if」條件句來檢查 age 是否位於 1490 的閉區間。

「閉區間」意味着,age 的值能夠取 1490

7. 檢測值是否位於範圍以外

重要程度:⭐️⭐️⭐

寫一個 if 條件句,檢查 age 是否不位於 14 到 90 的閉區間。

建立兩個表達式:第一個用非運算 !,第二個不用。

8. 一個關於 "if" 的問題

重要程度:⭐️⭐️⭐️⭐️⭐️

下面哪個 alert 將會被執行?

if(...) 語句內表達式的結果是什麼?

if (-1 || 0) alert( 'first' );
if (-1 && 0) alert( 'second' );
if (null || -1 && 1) alert( 'third' );
複製代碼

9. 登錄驗證

重要程度:⭐️⭐️⭐

實現使用 prompt 進行登錄校驗的代碼。

若是訪問者輸入 "Admin",那麼使用 prompt 引導獲取密碼,若是輸入的用戶名爲空或者按下了 key:Esc 鍵 —— 顯示 "Canceled",若是是其餘字符串 —— 顯示 "I don't know you"。

密碼的校驗規則以下:

  • 若是輸入的是 "TheMaster",顯示 "Welcome!",
  • 其餘字符串 —— 顯示 "Wrong password",
  • 空字符串或取消了輸入,顯示 "Canceled."。

流程圖:

請使用嵌套的 if 塊。注意代碼總體的可讀性。

提示:將空字符串輸入,prompt 會獲取到一個空字符串 ''。Prompt 運行過程當中,按下 key:ESC 鍵會獲得 null

答案:

在微信公衆號「技術漫談」後臺回覆 1-2-11 獲取本題答案。


現代 JavaScript 教程:開源的現代 JavaScript 從入門到進階的優質教程。React 官方文檔推薦,與 MDN 並列的 JavaScript 學習教程

在線免費閱讀:zh.javascript.info


掃描下方二維碼,關注微信公衆號「技術漫談」,訂閱更多精彩內容。

相關文章
相關標籤/搜索