Web前端入門第 58 問(wèn):JavaScript 運(yùn)算符 == 和 === 有什么區(qū)別?
運(yùn)算符
JavaScript 運(yùn)算符是真的多,尤其是 ES6 之后還在不停的加運(yùn)算符,其他編程語(yǔ)言看 JS 就像怪物一樣,各種騷操作不斷~~
運(yùn)算符分類
1、算術(shù)運(yùn)算符
算術(shù)運(yùn)算符的作用就是用來(lái)基礎(chǔ)計(jì)算,跟小學(xué)課本一樣,包含:加 +,減 -,乘 *,除 /,取余(也叫做取模) %,指數(shù) **,自增 ++,自減 --。
只是需注意:乘號(hào)不再是 x,除號(hào)也不再是 ÷!
與我們學(xué)過(guò)的運(yùn)算法則一樣,乘法與除法優(yōu)先級(jí)比加減法高,如果要改變優(yōu)先級(jí),需要使用括號(hào) (),只是一個(gè)算式中有多個(gè)括號(hào)還是使用小括號(hào),不用中括號(hào)而已。
// 加法
console.log(3 + 5); // 8
console.log(3 + '5'); // '35'(字符串拼接)
// 減法、乘法、除法
console.log(10 - 3); // 7
console.log(2 * 4); // 8
console.log(10 / 2); // 5
// 取余、指數(shù)
console.log(10 % 3); // 1(余數(shù))
console.log(2 ** 3); // 8(2的3次方)
// 自增/自減(注意前置與后置)
let a = 5;
console.log(a++); // 5(先返回原值,再自增)
console.log(++a); // 7(先自增,再返回新值)
// 使用括號(hào)改變優(yōu)先級(jí)
console.log((2 + 3) * 4); // 5 * 4 = 20
console.log(((2 + 3) - (5 -3)) * 4); // (5 - 2) * 4 = 12
2、比較運(yùn)算符
一般用于邏輯比較,比如比較兩個(gè)值是否相等,比較兩個(gè)數(shù)的大小等等。包含:等于 ==,嚴(yán)格等于(全等于) ===,不等于 !=,嚴(yán)格不等于(不全等) !==,大于 >,小于 <,大于等于 >=,小于等于 <=
需特別注意:== 與 != 會(huì)存在類型轉(zhuǎn)換,所以 JS 建議使用 === 與 !==。
// 松散比較(類型轉(zhuǎn)換)
console.log(5 == '5'); // true(值相等)
console.log(0 == false); // true(0和false在松散比較中等價(jià))
console.log(5 != '5'); // false(值相等)
// 嚴(yán)格比較(值和類型)
console.log(5 === '5'); // false(類型不同)
console.log(0 === false); // false(類型不同)
console.log(5 !== '5'); // true(類型不同)
// 其他比較
console.log(3 > 2); // true
console.log('apple' > 'banana'); // false(按字母順序比較)
console.log(2 >= 2); // true
console.log(2 <= 2); // true
如果要比較值類型不同,建議顯示轉(zhuǎn)換類型再用 === 比較。比如:
const a = 5;
const b = '5';
if (a + '' === '5') {} // 將 a 轉(zhuǎn)換為字符串再比較
if (b - 0 === 5) {} // 將 b 轉(zhuǎn)換為數(shù)字再比較
3、邏輯運(yùn)算符
用于邏輯判斷,包含:邏輯與 &&,邏輯或 ||,邏輯非 !。
需注意他們的短路特性。
// 邏輯與(&&):短路特性
console.log(true && 'Hello'); // 'Hello'(返回最后一個(gè)真值)
console.log(false && 'Hello'); // false(遇到假值直接返回)
// 邏輯或(||):短路特性
console.log(0 || 'default'); // 'default'(返回第一個(gè)真值)
console.log('A' || 'B'); // 'A'
// 邏輯非(!)
console.log(!true); // false
console.log(!!'非空字符串'); // true(強(qiáng)制轉(zhuǎn)布爾值)
// 應(yīng)用場(chǎng)景
// 默認(rèn)值設(shè)置
function greet(name) {
name = name || 'Guest'; // 若 name 為假值,返回 'Guest'
console.log(`Hello, ${name}!`);
}
greet(); // 'Hello, Guest!'
// 條件執(zhí)行函數(shù)
true && console.log('執(zhí)行了!'); // 輸出 '執(zhí)行了!'
false || console.log('執(zhí)行了!'); // 輸出 '執(zhí)行了!'
4、賦值運(yùn)算符
用于給變量賦值,包含:賦值(等于) =,加等于(累加) +=,減等于(累減) -=,乘等于(累乘) *=,除等于(累除) /=,模等于(累模) %=,冪等于(累冪) **=。
let x = 10;
x += 5; // x = x + 5 → 15
x *= 2; // x = 15 * 2 → 30
x **= 2; // x = 30^2 → 900
console.log(x); // 900
5、位運(yùn)算符
二進(jìn)制的位運(yùn)算符,據(jù)說(shuō)是最快的運(yùn)算符,當(dāng)然一般編程用不上,如果您用 JS 進(jìn)行大量的計(jì)算操作時(shí),比如:圖形圖像算法、加密算法等相關(guān)操作,這時(shí)候就必須需掌握位運(yùn)算了!包含:按位與 &,按位或 |,按位異或 ^,按位非 ~,左移 <<,右移 >>,無(wú)符號(hào)右移 >>>。
這部分運(yùn)算符涉及到底層的二進(jìn)制運(yùn)算,如果有興趣可以查找相關(guān)資料學(xué)習(xí)。
// 按位與(&)
console.log(5 & 3); // 1(二進(jìn)制 101 & 011 → 001)
// 按位或(|)
console.log(5 | 3); // 7(101 | 011 → 111)
// 無(wú)符號(hào)右移(>>>)
console.log(-1 >>> 0); // 4294967295(將負(fù)數(shù)轉(zhuǎn)為無(wú)符號(hào)整數(shù))
6、三元運(yùn)算符
又稱為三目運(yùn)算符(吐槽下:亂七八糟的名字特多),一般用于簡(jiǎn)化 if else 語(yǔ)句,但不建議過(guò)多嵌套,要不然代碼閱讀起來(lái)費(fèi)勁。
語(yǔ)法:condition ? expr1 : expr2。
const age = 20;
const canVote = age >= 18 ? 'Yes' : 'No';
console.log(canVote); // 'Yes'
// 等價(jià)于
if (age >= 18) {
console.log('Yes');
} else {
console.log('No');
}
// 三元運(yùn)算符的多次嵌套
const a = age > 80 ? '高齡老人' : (age > 60 ? '老年人' : (age > 40 ? '中年人' : '年輕人'))
可以看看多次嵌套的代碼是否是難以閱讀,為了項(xiàng)目的可維護(hù)性,真心不建議把三元運(yùn)算符用于多次嵌套。
7、特殊運(yùn)算符
JS 內(nèi)置的關(guān)鍵字,包含:typeof, instanceof, delete, void, in, new。
// typeof 返回變量的類型字符串
console.log(typeof 42); // 'number'
console.log(typeof null); // 'object'(歷史遺留問(wèn)題)
// instanceof 檢查對(duì)象是否是某個(gè)構(gòu)造函數(shù)的實(shí)例(基于原型鏈)
class Person {}
const p = new Person();
console.log(p instanceof Person); // true
// delete 刪除對(duì)象的屬性或數(shù)組元素(對(duì)變量無(wú)效)
const obj = { a: 1 };
delete obj.a; // 刪除屬性
console.log(obj.a); // undefined
// void 執(zhí)行表達(dá)式并返回 undefined
console.log(void (1 + 1)); // undefined
// in 檢查對(duì)象或其原型鏈中是否包含指定屬性
console.log('toString' in obj); // true(繼承自O(shè)bject.prototype)
// new 創(chuàng)建構(gòu)造函數(shù)實(shí)例(調(diào)用構(gòu)造函數(shù),綁定 this)
function Car(brand) {
this.brand = brand;
}
const myCar = new Car('Tesla');
console.log(myCar.brand); // 'Tesla'
/* 等價(jià)于以下過(guò)程:
1. 創(chuàng)建一個(gè)空對(duì)象 {}
2. 將空對(duì)象的原型指向 Car.prototype
3. 執(zhí)行 Car 函數(shù),this 指向該空對(duì)象
4. 返回新對(duì)象 */
8、ES6+ 運(yùn)算符
ES6 之后新增的一些運(yùn)算符,騷操作從這里開始。包含:展開運(yùn)算符 ..., 可選鏈 ?., 空值合并 ??
// 展開運(yùn)算符(...)
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5, 6];
console.log(...arr1); // 1 2 3
console.log(arr2); // [1, 2, 3, 4, 5, 6]
// 可選鏈(?.)
const user = { address: { city: 'Paris' } };
console.log(user?.address?.city); // 'Paris'
console.log(user?.phone?.number); // undefined(不會(huì)報(bào)錯(cuò))
// 空值合并(??)
const input = null;
const value = input ?? 'default'; // 'default'(僅針對(duì) null/undefined)
類型轉(zhuǎn)換規(guī)則
當(dāng)操作數(shù)類型不同時(shí),JS 會(huì)按內(nèi)部規(guī)則嘗試進(jìn)行類型轉(zhuǎn)換:
const obj = { toString: () => '100' };
// 調(diào)用 valueOf() → toString(),若結(jié)果為原始值則繼續(xù)比較
console.log(obj > 50); // true('100' → 100 > 50)
// true → 1,false → 0
console.log(true > -1); // true(1 > -1)
console.log(false < 1); // true(0 < 1)
// null → 0
console.log(null > -1); // true(0 > -1)
// undefined → NaN
console.log(undefined > 0); // false(NaN 與任何值比較均為 false)
// 若字符串為合法數(shù)字 → 轉(zhuǎn)換為數(shù)字,否則 → NaN
console.log('123' > 50); // true(123 > 50)
console.log('abc' > 0); // false('abc' → NaN)
// 對(duì)象與非對(duì)象比較
const arr = [10];
console.log(arr > 5); // true([10].toString() → '10' → 10 > 5)
// 十六進(jìn)制字符串
console.log('0x1f' > 30); // true('0x1f' → 31 > 30)
// 空字符串與 0
console.log('' > -1); // true('' → 0 > -1)
console.log(0 == ''); // true(0 == 0)
// 布爾值的陷阱
console.log(true == '1'); // true(1 == 1)
console.log(false == '0'); // true(0 == 0)
console.log([1] > 0); // true([1].toString() → '1' → 1 > 0)
console.log([] > -1); // true([].toString() → '' → 0 > -1)
console.log([] == 0); // true(0 == 0)
console.log([] == false); // true(0 == 0)
常見問(wèn)題
1、== 和 === 的區(qū)別是什么?
答:== 會(huì)進(jìn)行類型轉(zhuǎn)換后比較,=== 嚴(yán)格比較值和類型。
2、邏輯運(yùn)算符 && 和 || 的返回值是什么?
答:返回第一個(gè)決定表達(dá)式結(jié)果的子表達(dá)式值(短路求值)。
3、1 + '1' 和 '1' + 1 的結(jié)果是什么?
答:均為 '11'(字符串拼接)。
4、0 == false 和 '' == false 的結(jié)果是什么?為什么?
答:均為 true,因 == 會(huì)進(jìn)行隱式轉(zhuǎn)換。
5、typeof null 返回什么?為什么?
答:'object'(歷史遺留問(wèn)題)。
6、可選鏈 ?. 和空值合并 ?? 的作用是什么?
答:obj?.prop 避免訪問(wèn) null/undefined,a ?? b 僅在 a 為 null/undefined 時(shí)返回 b。
7、以下代碼的輸出是什么?
console.log(1 < 2 < 3); // true(等價(jià)于 (1 < 2) < 3 → true < 3 → 1 < 3 → true)
console.log(3 > 2 > 1); // false(等價(jià)于 (3 > 2) > 1 → true > 1 → 1 > 1 → false)
8、console.log(!!' ') 的輸出是什么?
答:true(非空字符串轉(zhuǎn)布爾值為 true)。
9、如何用短路求值簡(jiǎn)化代碼?
const value = input || defaultValue;
10、如何安全訪問(wèn)嵌套對(duì)象屬性?
答:使用可選鏈 obj?.a?.b ?? 'default'。
寫在最后
優(yōu)先使用 === 和 !== 避免 JS 的隱式轉(zhuǎn)換帶來(lái)的不確定性。
隱式轉(zhuǎn)換機(jī)制需特別注意,特別是在處理用戶輸入、API 接口響應(yīng)數(shù)據(jù)時(shí),稍不注意就掉坑了!!
如果您有大量計(jì)算工作量,那么必須啃書二進(jìn)制的位運(yùn)算符,否則使用十進(jìn)制運(yùn)算會(huì)拖慢程序運(yùn)行速度。
文章首發(fā)于微信公眾號(hào)【前端路引】,歡迎 微信掃一掃 查看更多文章。
本文來(lái)自博客園,作者:前端路引,轉(zhuǎn)載請(qǐng)注明原文鏈接:http://www.rzrgm.cn/linx/p/18896521

浙公網(wǎng)安備 33010602011771號(hào)