一、概念
與其他語言不同,在js中,邏輯運算符可以返回任何類型的數據,不僅僅是true和false。
&&和||的返回值是兩個操作數的其中一個。即a&&b或者a||b返回的是要么是a,要么是b,而其他語言中返回的是true or false。
在js邏輯運算中,需要隱式的轉換為boolean類型再來運算,轉換規則為:
1. 對象、非零number、非空string——>true
2. 0、""、null、false、undefined、NaN——>false
具體見下表:
數據類型 |
轉換為boolean后的值 |
NAN | FALSE |
null | FALSE |
undefined | FALSE |
Object | TRUE |
Function | TRUE |
0 | FALSE |
非零的數字 | TRUE |
""(空字符串) | FALSE |
非空字符串 | TRUE |
因此:
a && b : 將a, b轉換為Boolean類型, 再執行邏輯與, 如果結果是true返回b, false返回a
a || b : 將a, b轉換為Boolean類型, 再執行邏輯或, 如果結果是false返回b, true返回第一個為true的值。
邏輯&&和邏輯||還有一個短路原則:知道了前面第一個的結果就知道最后的輸出
a&&b:左操作數為假值時,返回左操作數,否則返回右操作數。
a||b:左操作數為假值時,返回右操作數,否則返回左操作數。
只要“||”前面為false,不管“||”后面是true還是false,都返回“||”后面的值。
只要“||”前面為true,不管“||”后面是true還是false,都返回“||”前面的值。
只要“&&”前面是false,無論“&&”后面是true還是false,結果都將返“&&”前面的值;
只要“&&”前面是true,無論“&&”后面是true還是false,結果都將返“&&”后面的值;
同樣對於多個操作數的情況:
a||b||c||d:若結果為true則返回第一個true值,若結果為false則返回最后一個操作數。eg:var a = “” || null || 3 || 2 -> var a = fasel || false || true || true 結果為true 則返回第一個true,即是3
a&&b&&c&&d:若結果為false則返回第一個false,若結果為true則返回最后一個操作數。eg:var b = 2&&null&&1&&0 -> var b = true&&false&&true&&false結果是false 則返回第一個false 即是null
二、理解
“&&”和“||”運算符均可以從三個不同的層次來逐步理解:
以“&&”為例解釋如下:
(1)最簡單的第一層理解是,當操作數都是布爾值的時候,“&&”對兩個值執行布爾與(AND)操作,只有在第一個操作數和第二個操作數都是true的時候,它才返回true。如果其中一個操作數是false,它返回false。
(2)“&&”的操作數並不一定是布爾值。於是對“&&”的第二層理解是,“&&”可以對真值和假值進行布爾與(AND)操作。如果兩個操作數都是真值,那么返回一個真值;否則,至少一個操作數是假值的話,則返回一個假值。在JavaScript中任何希望使用布爾值的地方,表達式和語句都會將其當做真值或假值來對待,因此實際上“&&”並不總是返回true和false。
(3)第三層理解,運算符首先計算左操作數的值,即首先計算“&&”左側的表達式。如果計算結果是假值,那么整個表達式的結果一定也是假值,因此“&&”這時簡單地返回左操作數的值,而並不會對右操作數進行計算。反過來講,如果左操作數是真值,那么整個表達式的結果則依賴於右操作數的值。如果右操作數是真值,那么整個表達式的值一定是真值;如果右操作數是假值,那么整個表達式的值一定是假值。
理解如下例子對於理解“&&”可能不會去計算右操作數的情況至關重要,在以下示例代碼中,變量p的值是null,而如果計算表達式p.x的話則會拋出一個類型錯誤異常。但是示例代碼使用了“&&”的一種符合語言習慣的用法,因此只有在p為真值(不能是null或者undefined)的情況下才會計算p.x。反過來,我們一般需要用某個對象p中的某個元素時,為了嚴謹也應該先對其是否存在進行判斷。
var o = { x : 1 }; var p = null; o && o.x // =>1:o 是真值,因此返回值為o.x p && p.x //=>null: p是假值,因此將其返回,而並不去計算p.x
三、使用場景
1.||運算符最常用的方式是用來從一組備選表達式中選出第一個真值表達式,即從一系列值中獲取第一個true值。
// 如果max_width已經定義了,直接使用它;否則在preferences對象中查找max_width;如果沒有定義它,則使用一個寫死的常量 var max = max_width || preferences.max_width || 500;
2.判斷某個元素是否存在時:if(attr)寫成if(!!attr)更加嚴謹。
!!的作用是把一個其他類型的變量轉成的bool類型。eg:
typeof 5//"number" typeof !!5//"boolean"
3.對函數中的參數賦以默認值:a=a||
"defaultValue"
;
例如當a不存在或不合法時為其賦默認值,比起如下兩種寫法:
if(!a){ a="defaultValue"; }
if(a==null||a==""||a==undefined){ a="defaultValue"; }
用||一句話就可以實現,簡單又優雅:
a=a||"defaultValue";
4.利用&&的短路特性有條件的執行代碼
(1)在回調中,經常這樣寫:callback&&callback(),先判斷 callback 是不是存在,存在才執行,這樣寫更加嚴謹,如果直接寫 callback(); 當callback不存在時代碼就會報錯。
(2)又或者常見的條件語句:if
(a==b) stop();如果用&&來實現即為:
(a==b)&&stop();
(3)判斷某個對象存在再取值:p && p.x
應用舉例:
如圖:
假設對成長速度顯示規定如下:
成長速度為5顯示1個箭頭;
成長速度為10顯示2個箭頭;
成長速度為12顯示3個箭頭;
成長速度為15顯示4個箭頭;
其他都顯示都顯示0個箭頭。
(1)最容易想到也最常規的方法:if-else
var add_level = 0; if(add_step == 5){ add_level = 1; } else if(add_step == 10){ add_level = 2; } else if(add_step == 12){ add_level = 3; } else if(add_step == 15){ add_level = 4; } else { add_level = 0; }
(2)switch方法:
var add_level = 0; switch(add_step){ case 5 : add_level = 1; break; case 10 : add_level = 2; break; case 12 : add_level = 3; break; case 15 : add_level = 4; break; default : add_level = 0; break; }
(3)而如果用&&和||就會超級簡單:
var add_level = (add_step==5 && 1) || (add_step==10 && 2) || (add_step==12 && 3) || (add_step==15 && 4) || 0;
優化為:
var add_level={'5':1,'10':2,'12':3,'15':4}[add_step] || 0; //對象取值有兩種方式,一種object.key,一種是object[key],此處為法二
特別是如果需求改成:
成長速度為>12顯示4個箭頭;
成長速度為>10顯示3個箭頭;
成長速度為>5顯示2個箭頭;
成長速度為>0顯示1個箭頭;
成長速度為<=0顯示0個箭頭。
那么用switch實現起來也很麻煩了,而同樣用&&和||只要如下即可。
var add_level = (add_step>12 && 4) || (add_step>10 && 3) || (add_step>5 && 2) || (add_step>0 && 1) || 0;
注:與&&和||不同,!操作符的行為與C、Java等語言是一致的,只返回boolean值(true或false)。
參考:
http://www.cnblogs.com/yanayana/p/7079345.html
全面解析JavaScript中“&&”和“||”操作符(總結篇)