// 值的比較
// 比較結(jié)果為 Boolean 類型
// 所有比較運(yùn)算符均返回布爾值:
// true —— 表示“yes(是)”,“correct(正確)”或“the truth(真)”。
// false —— 表示“no(否)”,“wrong(錯(cuò)誤)”或“not the truth(非真)”。
alert(2 >1 );? // true(正確)
alert(2 ==1 ); // false(錯(cuò)誤)
alert(2 !=1 ); // true(正確)
let result =5 >4; // 把比較的結(jié)果賦值給 result
alert(result ); // true
// 字符串比較
alert('Z' >'A' ); // true
alert('Glow' >'Glee' ); // true
alert('Bee' >'Be' ); // true
// 在上面的第一個(gè)例子中,'Z' > 'A' 比較在算法的第 1 步就得到了結(jié)果。
// 在第二個(gè)例子中,字符串 Glow 與 Glee 的比較則需要更多步驟,因?yàn)樾枰饌€(gè)字符進(jìn)行比較:
// G 和 G 相等。
// l 和 l 相等。
// o 比 e 大,算法停止,第一個(gè)字符串大于第二個(gè)。
// 字符串的比較算法非常簡(jiǎn)單:
// 首先比較兩個(gè)字符串的首位字符大小。
// 如果一方字符較大(或較?。?,則該字符串大于(或小于)另一個(gè)字符串。算法結(jié)束。
// 否則,如果兩個(gè)字符串的首位字符相等,則繼續(xù)取出兩個(gè)字符串各自的后一位字符進(jìn)行比較。
// 重復(fù)上述步驟進(jìn)行比較,直到比較完成某字符串的所有字符為止。
// 如果兩個(gè)字符串的字符同時(shí)用完,那么則判定它們相等,否則未結(jié)束(還有未比較的字符)的字符串更大
// 在上面的算法中,比較大小的邏輯與字典或電話簿中的排序很像,但也不完全相同。
// 比如說(shuō),字符串比較對(duì)字母大小寫是敏感的。大寫的 "A" 并不等于小寫的 "a"。哪一個(gè)更大呢?實(shí)際上小寫的 "a" 更大。這是因?yàn)樵?JavaScript 使用的內(nèi)部編碼表中(Unicode),小寫字母的字符索引值更大。我們會(huì)在 字符串 這章討論更多關(guān)于字符串的細(xì)節(jié)。
// 不同類型間的比較
// 當(dāng)對(duì)不同類型的值進(jìn)行比較時(shí),JavaScript 會(huì)首先將其轉(zhuǎn)化為數(shù)字(number)再判定大小。
alert('2' >1 ); // true,字符串 '2' 會(huì)被轉(zhuǎn)化為數(shù)字 2
alert('01' ==1 ); // true,字符串 '01' 會(huì)被轉(zhuǎn)化為數(shù)字 1
alert(true ==1 ); // true
alert(false ==0 ); // true
let a =0
alert(Boolean(a))// false
let b ="0"
alert(Boolean(b))// true
alert(a ==b)// true
// 嚴(yán)格相等
// 普通的相等性檢查 == 存在一個(gè)問(wèn)題,它不能區(qū)分出 0 和 false:
alert(0 ==false ); // true
alert('' ==false ); // true
// 嚴(yán)格相等運(yùn)算符 === 在進(jìn)行比較時(shí)不會(huì)做任何的類型轉(zhuǎn)換。
alert(0 ===false ); // false,因?yàn)楸槐容^值的數(shù)據(jù)類型不同
// 同樣的,與“不相等”符號(hào) != 類似,“嚴(yán)格不相等”表示為 !==。
// 嚴(yán)格相等的運(yùn)算符雖然寫起來(lái)稍微長(zhǎng)一些,但是它能夠很清楚地顯示代碼意圖,降低你犯錯(cuò)的可能性。
// 對(duì) null 和 undefined 進(jìn)行比較
alert(null ===undefined ); // false
alert(null ==undefined ); // true
// 當(dāng)使用數(shù)學(xué)式或其他比較方法 < > <= >= 時(shí):
// null/undefined 會(huì)被轉(zhuǎn)化為數(shù)字:null 被轉(zhuǎn)化為 0,undefined 被轉(zhuǎn)化為 NaN。
alert(null >0 );? // (1) false
alert(null ==0 ); // (2) false
alert(null >=0 ); // (3) true
// 是的,上面的結(jié)果完全打破了你對(duì)數(shù)學(xué)的認(rèn)識(shí)。在最后一行代碼顯示“null 大于等于 0”的情況下,前兩行代碼中一定會(huì)有一個(gè)是正確的,然而事實(shí)表明它們的結(jié)果都是 false。
// 比較運(yùn)算符始終返回布爾值。
// 字符串的比較,會(huì)按照“詞典”順序逐字符地比較大小。
// 當(dāng)對(duì)不同類型的值進(jìn)行比較時(shí),它們會(huì)先被轉(zhuǎn)化為數(shù)字(不包括嚴(yán)格相等檢查)再進(jìn)行比較。
// 在非嚴(yán)格相等 == 下,null 和 undefined 相等且各自不等于任何其他的值。
// 在使用 > 或 < 進(jìn)行比較時(shí),需要注意變量可能為 null/undefined 的情況。比較好的方法是單獨(dú)檢查變量是否等于 null/undefined。
// 5 > 4 → true
// "apple" > "pineapple" → false
// "2" > "12" → true
// undefined == null → true
// undefined === null → false
// null == "\n0\n" → false
// null === +"\n0\n" → false
// 結(jié)果的原因:
// 數(shù)字間比較大小,顯然得 true。
// 按詞典順序比較,得 false。"a" 比 "p" 小。
// 與第 2 題同理,首位字符 "2" 大于 "1"。
// null 只與 undefined 互等。
// 嚴(yán)格相等模式下,類型不同得 false。
// 與第 4 題同理,null 只與 undefined 相等。
// 不同類型嚴(yán)格不相等。
// 條件分支:if 和 '?'
let year =prompt("hahah","")
if (year ==2015)alert("xxxxx")// 單個(gè)語(yǔ)句
if (year ==2016) {
alert("xxxx")
alert("xxxxx")
}//建議每次使用 if 語(yǔ)句都用大括號(hào) {} 來(lái)包裝代碼塊,即使只有一條語(yǔ)句。這樣可以提高代碼可讀性。
// 布爾轉(zhuǎn)換
if (0) {//0 是假值 false
// xxx 、
}
if (1) {// 1 是真值(truthy)
...
}
let year =prompt('In which year was ECMAScript-2015 specification published?', '');
if (year ==2015) {
alert('You guessed it right!' );
}else {
alert('How can you be so wrong?' ); // 2015 以外的任何值
}
if (year <2015) {
alert('Too early...' );
}else if (year >2015) {
alert('Too late' );
}else {
alert('Exactly!' );
}
// 條件運(yùn)算符 ‘?’
let accessAllowed;
let age =prompt('How old are you?', '');
if (age >18) {
accessAllowed =true;
}else {
accessAllowed =false;
}
alert(accessAllowed);
// 簡(jiǎn)寫為:
let condition =true
// let result = condition ? value1 : value2; 計(jì)算條件結(jié)果,如果結(jié)果為真,則返回 value1,否則返回 value2。
// 多個(gè) ‘?’
let age =prompt("age?","18")
let message = (age <3) ?'xxx' : (age <18) ?"21212" : (age <100) ?'121212' :"12121221"
alert(message );
// let message;
// if (login == 'Employee') {
//? ? message = 'Hello';
// } else if (login == 'Director') {
//? ? message = 'Greetings';
// } else if (login == '') {
//? ? message = 'No login';
// } else {
//? ? message = '';
// }
// let message = (login == 'Employee') ? 'Hello' :
//? ? (login == 'Director') ? 'Greetings' :
//? ? ? ? (login == '') ? 'No login' :
//? ? ? ? ? ? '';
// 邏輯運(yùn)算符
// 或運(yùn)算尋找第一個(gè)真值
// 或運(yùn)算符 || 做了如下的事情:
// 從左到右依次計(jì)算操作數(shù)。
// 處理每一個(gè)操作數(shù)時(shí),都將其轉(zhuǎn)化為布爾值。如果結(jié)果是 true,就停止計(jì)算,返回這個(gè)操作數(shù)的初始值。
// 如果所有的操作數(shù)都被計(jì)算過(guò)(也就是,轉(zhuǎn)換結(jié)果都是 false),則返回最后一個(gè)操作數(shù)。
// 返回的值是操作數(shù)的初始形式,不會(huì)做布爾轉(zhuǎn)換。
// 換句話說(shuō),一個(gè)或運(yùn)算 || 的鏈,將返回第一個(gè)真值,如果不存在真值,就返回該鏈的最后一個(gè)值。
// 例如:
alert(1 ||0 ); // 1(1 是真值)
alert(null ||1 ); // 1(1 是第一個(gè)真值)
alert(null ||0 ||1 ); // 1(第一個(gè)真值)
alert(undefined ||null ||0 ); // 0(都是假值,返回最后一個(gè)值)
// 獲取變量列表或者表達(dá)式中的第一個(gè)真值。
// 例如,我們有變量 firstName、lastName 和 nickName,都是可選的(即可以是 undefined,也可以是假值)。
// 我們用或運(yùn)算 || 來(lái)選擇有數(shù)據(jù)的那一個(gè),并顯示出來(lái)(如果沒(méi)有設(shè)置,則用 "Anonymous"):
let firstName ="";
let lastName ="";
let nickName ="SuperCoder";
alert(firstName ||lastName ||nickName ||"Anonymous"); //如果所有變量的值都為假,結(jié)果就是 "Anonymous"。
// 短路求值(Short-circuit evaluation)。
// 或運(yùn)算符 || 的另一個(gè)用途是所謂的“短路求值”。
// 這指的是,|| 對(duì)其參數(shù)進(jìn)行處理,直到達(dá)到第一個(gè)真值,然后立即返回該值,而無(wú)需處理其他參數(shù)。
// 如果操作數(shù)不僅僅是一個(gè)值,而是一個(gè)有副作用的表達(dá)式,例如變量賦值或函數(shù)調(diào)用,那么這一特性的重要性就變得顯而易見(jiàn)了。
// 在下面這個(gè)例子中,只會(huì)打印第二條信息:
true ||alert("not printed");
false ||alert("printed");
// 在第一行中,或運(yùn)算符 || 在遇到 true 時(shí)立即停止運(yùn)算,所以 alert 沒(méi)有運(yùn)行。
// 有時(shí),人們利用這個(gè)特性,只在左側(cè)的條件為假時(shí)才執(zhí)行命令。
// && 與運(yùn)算尋找第一個(gè)假值
// result = value1 && value2 && value3;
// 與運(yùn)算 && 做了如下的事:
// 從左到右依次計(jì)算操作數(shù)。
// 在處理每一個(gè)操作數(shù)時(shí),都將其轉(zhuǎn)化為布爾值。如果結(jié)果是 false,就停止計(jì)算,并返回這個(gè)操作數(shù)的初始值。
// 如果所有的操作數(shù)都被計(jì)算過(guò)(例如都是真值),則返回最后一個(gè)操作數(shù)。
// 換句話說(shuō),與運(yùn)算返回第一個(gè)假值,如果沒(méi)有假值就返回最后一個(gè)值。
// 上面的規(guī)則和或運(yùn)算很像。區(qū)別就是與運(yùn)算返回第一個(gè)假值,而或運(yùn)算返回第一個(gè)真值。
// 如果第一個(gè)操作數(shù)是真值,
// 與運(yùn)算返回第二個(gè)操作數(shù):
alert(1 &&0 ); // 0
alert(1 &&5 ); // 5
// 如果第一個(gè)操作數(shù)是假值,
// 與運(yùn)算將直接返回它。第二個(gè)操作數(shù)會(huì)被忽略
alert(null &&5 ); // null
alert(0 &&"no matter what" ); // 0
alert(1 &&2 &&null &&3 ); // null
alert(1 &&2 &&3 ); // 3,最后一個(gè)值
// 與運(yùn)算 && 在或運(yùn)算 || 之前進(jìn)行
// 與運(yùn)算 && 的優(yōu)先級(jí)比或運(yùn)算 || 要高。
// 所以代碼 a && b || c && d 跟 && 表達(dá)式加了括號(hào)完全一樣:(a && b) || (c && d)。
!(非)
// 感嘆符號(hào) ! 表示布爾非運(yùn)算符。
alert( !true ); // false
alert( !0 ); // true
// 兩個(gè)非運(yùn)算 !! 有時(shí)候用來(lái)將某個(gè)值轉(zhuǎn)化為布爾類型:
alert( !!"non-empty string" ); // true
alert( !!null ); // false
// 非運(yùn)算符 ! 的優(yōu)先級(jí)在所有邏輯運(yùn)算符里面最高,所以它總是在 && 和 || 之前執(zhí)行。
// let userName = prompt("Who's there?", '');
// if (userName === 'Admin') {
//? ? let pass = prompt('Password?', '');
//? ? if (pass === 'TheMaster') {
//? ? ? ? alert( 'Welcome!' );
//? ? } else if (pass === '' || pass === null) {
//? ? ? ? alert( 'Canceled' );
//? ? } else {
//? ? ? ? alert( 'Wrong password' );
//? ? }
// } else if (userName === '' || userName === null) {
//? ? alert( 'Canceled' );
// } else {
//? ? alert( "I don't know you" );
// }
// 空值合并運(yùn)算符 '??'
// ?? 運(yùn)算符的優(yōu)先級(jí)非常低,僅略高于 ? 和 =,因此在表達(dá)式中使用它時(shí)請(qǐng)考慮添加括號(hào)。
// 空值合并運(yùn)算符(nullish coalescing operator)的寫法為兩個(gè)問(wèn)號(hào) ??。
// 由于它對(duì)待 null 和 undefined 的方式類似,所以在本文中我們將使用一個(gè)特殊的術(shù)語(yǔ)對(duì)其進(jìn)行表示。我們將值既不是 null 也不是 undefined 的表達(dá)式稱為“已定義的(defined)”。
// a ?? b 的結(jié)果是:
// 如果 a 是已定義的,則結(jié)果為 a,
// 如果 a 不是已定義的,則結(jié)果為 b。
// let user;
// alert(user ?? "匿名"); // 匿名(user 未定義)
// let user = "John";
// alert(user ?? "匿名"); // John(user 已定義)