JavaScript中強(qiáng)大的操作符使用詳解
JavaScript 為我們提供了很多操作符,用于操作表達(dá)式。下面就來盤點(diǎn)一下 JavaScript 中那些強(qiáng)大的操作符!
一、一元操作符
操作符可以根據(jù)他們期待的操作符個(gè)數(shù)來分類,多數(shù)的JavaScript操作符都是二元操作符,二元操作符可以將兩個(gè)表達(dá)式合成一個(gè)更復(fù)雜的表達(dá)式。JavaScript也支持一元操作符,這些操作符可以將一個(gè)表達(dá)式轉(zhuǎn)化為另一個(gè)更復(fù)雜的表達(dá)式。同時(shí),JavaScript中也有一個(gè)三元操作符,就是條件操作符(?:),它用于將三個(gè)表達(dá)式組成一個(gè)表達(dá)式。下面就先來看看一元操作符。
一元操作符具有以下特點(diǎn):
- 最簡單的操作符,用來操作一個(gè)表達(dá)式;
- 具有高優(yōu)先級(jí)和右結(jié)合性;
- 在必要時(shí)將操作數(shù)自動(dòng)轉(zhuǎn)化為數(shù)值。
1. 遞增和遞減操作符(++ --)
遞增操作符顧名思義就是遞增其操作數(shù),遞減操作符就是遞減其操作數(shù)。它們都有兩個(gè)版本:
- 前綴版(++i):操作符位于變量的前面,表示先遞增(遞減),后執(zhí)行語句;
- 后綴版(i++):操作符位于變量的后面,表示先執(zhí)行語句,后遞增(遞減);
簡單看兩個(gè)例子:
//?前置遞增操作符: let?num1?=?1,?num2?=?2; console.log(++num1?+?num2)?//?4 //?后置遞增操作符: let?num1?=?1,?num2?=?2; console.log(num1++?+?num2)?//?3
可以看到,兩種類型的結(jié)果是不一樣的,原因就在于后置遞增遞減操作是在包含它們的語句被求值之后才執(zhí)行的。
這四個(gè)操作符可以作用于任何類型的數(shù)據(jù)。對(duì)于這些類型,JavaScript會(huì)將他們轉(zhuǎn)化為數(shù)值,再在這個(gè)數(shù)值上進(jìn)行加一或減一操作。如果不能轉(zhuǎn)化為一個(gè)數(shù)字,那么遞增或遞減的結(jié)果就是NaN:
let?str?=?"hello"; console.log(str++)??//?NaN
遞增和遞減操作符主要用于for循環(huán)中控制計(jì)算器遞增或遞減。
2. 加和減操作符
加和減操作符既是一元操作符,也是二元操作符。這里我們先來看一元加和減操作符。
(1)一元加運(yùn)算符(+)
一元加操作符會(huì)將其操作數(shù)轉(zhuǎn)化為數(shù)值,并返回轉(zhuǎn)化后的值。需要注意:
- 如果操作數(shù)是數(shù)值,那它什么都不做;
- 如果操作數(shù)不能轉(zhuǎn)化為數(shù)值,那么會(huì)返回NaN;
- 由于BigInt值不能轉(zhuǎn)化為數(shù)值,因此這個(gè)操作符不能用于BigInt。
let?a?=?-1; let?b?=?"hello"; let?c?=?BigInt; console.log(+a)??//?-1 console.log(+b)??//?NaN console.log(+c)??//?NaN
(2)一元減運(yùn)算符(-)
一元減操作符和一元加操作符類似,會(huì)先將操作數(shù)轉(zhuǎn)化為數(shù)值,然后會(huì)改變結(jié)果的符號(hào):
let?a?=?-1; let?b?=?2; console.log(-a)??//?1 console.log(-b)??//?-2
一元加和減操作符主要用于基本的算術(shù)運(yùn)算,也可以用于數(shù)據(jù)類型的轉(zhuǎn)換,將不同類型的數(shù)據(jù)轉(zhuǎn)化為數(shù)字類型,像Number()方法一樣。
二、位操作符
現(xiàn)代計(jì)算機(jī)中數(shù)據(jù)都是以二進(jìn)制的形式存儲(chǔ)的,即0、1兩種狀態(tài),計(jì)算機(jī)對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行的運(yùn)算加減乘除等都是叫位運(yùn)算,即將符號(hào)位共同參與運(yùn)算的運(yùn)算。
JavaScript中所有的數(shù)字都是以IEEE 754 64位格式存儲(chǔ),但是位操作并不直接應(yīng)用到64位,而是先將值轉(zhuǎn)化為32位整數(shù),再進(jìn)行位操作。之后再把運(yùn)算結(jié)果轉(zhuǎn)化為64位,所以我們只需要考慮32位整數(shù)即可。位操作是在數(shù)值的底層完成的,所以運(yùn)算速度會(huì)相對(duì)于其他運(yùn)算符快很多。
常見的位運(yùn)算有以下幾種:
運(yùn)算符 | 描述 | 運(yùn)算規(guī)則 |
---|---|---|
&` | 與 | 兩個(gè)位都為1時(shí),結(jié)果才為1 |
| | 或 | 兩個(gè)位都為0時(shí),結(jié)果才為0 |
^ | 異或 | 兩個(gè)位相同為0,相異為1 |
~ | 取反 | 0變1,1變0 |
<< | 左移 | 各二進(jìn)制位全部左移若干位,高位丟棄,低位補(bǔ)0 |
>> | 右移 | 各二進(jìn)制位全部右移若干位,正數(shù)左補(bǔ)0,負(fù)數(shù)左補(bǔ)1,右邊丟棄 |
在說這些操作符之前,先來看幾個(gè)相關(guān)的概念。計(jì)算機(jī)中的有符號(hào)數(shù)有三種表示方法,即原碼、反碼和補(bǔ)碼。三種表示方法均有符號(hào)位和數(shù)值位兩部分,符號(hào)位都是用0表示“正”,用1表示“負(fù)”,而數(shù)值位,三種表示方法各不相同。
(1)原碼
原碼就是一個(gè)數(shù)的二進(jìn)制數(shù)。例如:10的原碼為0000 1010
(2)反碼
- 正數(shù)的反碼與原碼相同,如:10 反碼為 0000 1010
- 負(fù)數(shù)的反碼為除符號(hào)位,按位取反,即0變1,1變0。
例如,-10的反碼如下:
原碼:1000 1010
反碼:1111 0101
(3)補(bǔ)碼
- 正數(shù)的補(bǔ)碼與原碼相同,如:10 補(bǔ)碼為 0000 1010
- 負(fù)數(shù)的補(bǔ)碼是原碼除符號(hào)位外的所有位取反即0變1,1變0,然后加1,也就是反碼加1。
例如,-10的補(bǔ)碼如下:
原碼:1000 1010
反碼:1111 0101
補(bǔ)碼:1111 0110
1. 按位與操作符(&)
按位與操作符(&)會(huì)對(duì)參加運(yùn)算的兩個(gè)數(shù)據(jù)按二進(jìn)制位進(jìn)行與運(yùn)算,即兩位同時(shí)為 1 時(shí),結(jié)果才為1,否則結(jié)果為0。運(yùn)算規(guī)則如下:
0?&?0?=?0?? 0?&?1?=?0?? 1?&?0?=?0?? 1?&?1?=?1
例如,3 & 5 的運(yùn)算結(jié)果如下:
0000 0011
0000 0101
= 0000 0001
因此 3 & 5 的值為 1。需要注意:負(fù)數(shù)按補(bǔ)碼形式參加按位與運(yùn)算。
用途:
(1)判斷奇偶
只要根據(jù)最未位是0還是1來決定,為0就是偶數(shù),為1就是奇數(shù)。因此可以用if ((i & 1) === 0)
代替if (i % 2 === 0)
來判斷a是不是偶數(shù)。
(2)清零
如果想將一個(gè)單元清零,即使其全部二進(jìn)制位為0,只要與一個(gè)各位都為零的數(shù)值相與,結(jié)果為零。
2. 按位或操作符(|)
按位或操作符(|)會(huì)對(duì)參加運(yùn)算的兩個(gè)對(duì)象按二進(jìn)制位進(jìn)行或運(yùn)算,即參加運(yùn)算的兩個(gè)對(duì)象只要有一個(gè)為1,其值為1。運(yùn)算規(guī)則如下:
0?|?0?=?0 0?|?1?=?1?? 1?|?0?=?1?? 1?|?1?=?1
例如,3 | 5 的運(yùn)算結(jié)果如下:
0000 0011
0000 0101
= 0000 0111
因此,3 | 5的值為7。需要注意:負(fù)數(shù)按補(bǔ)碼形式參加按位或運(yùn)算。
3. 按位非操作符 (~)
按位非操作符 (~)會(huì)對(duì)參加運(yùn)算的一個(gè)數(shù)據(jù)按二進(jìn)制進(jìn)行取反運(yùn)算。即將0變成1,1變成0。運(yùn)算規(guī)則如下:
~?1?=?0 ~?0?=?1
例如:~6 的運(yùn)算結(jié)果如下:
0000 0110
= 1111 1001
在計(jì)算機(jī)中,正數(shù)用原碼表示,負(fù)數(shù)使用補(bǔ)碼存儲(chǔ),首先看最高位,最高位1表示負(fù)數(shù),0表示正數(shù)。此計(jì)算機(jī)二進(jìn)制碼為負(fù)數(shù),最高位為符號(hào)位。
當(dāng)按位取反為負(fù)數(shù)時(shí),就直接取其補(bǔ)碼,變?yōu)槭M(jìn)制:
0000 0110
= 1111 1001
反碼:1000 0110
補(bǔ)碼:1000 0111
因此,~6的值為-7。按位非的操作結(jié)果實(shí)際上是對(duì)數(shù)值進(jìn)行取反并減1,
4. 按位異或運(yùn)算符(^)
按位異或運(yùn)算符(^)會(huì)對(duì)參加運(yùn)算的兩個(gè)數(shù)據(jù)按二進(jìn)制位進(jìn)行“異或”運(yùn)算,即如果兩個(gè)相應(yīng)位相同則為0,相異則為1。運(yùn)算規(guī)則如下:
0?^?0?=?0?? 0?^?1?=?1?? 1?^?0?=?1?? 1?^?1?=?0
例如, 3 ^ 5的運(yùn)算結(jié)果如下:
0000 0011
0000 0101
= 0000 0110
因此,3^5的值為6。
異或運(yùn)算具有以下性質(zhì):
- 交換律:
(a^b)^c == a^(b^c)
- 結(jié)合律:
(a + b)^c == a^b + b^c
- 對(duì)于任何數(shù)x,都有
x^x=0,x^0=x
- 自反性:
a^b^b=a^0=a
;
5. 左移操作符(<<)
左移操作符(<<)會(huì)將運(yùn)算對(duì)象的各二進(jìn)制位全部左移若干位,左邊的二進(jìn)制位丟棄,右邊補(bǔ)0。若左移時(shí)舍棄的高位不包含1,則每左移一位,相當(dāng)于該數(shù)乘以2。
例如:
a?=?1010?1110 a?=?a?<<?2
這里將a的二進(jìn)制位左移2位、右補(bǔ)0,即得 a = 1011 1000。
需要注意,左移會(huì)保留他所操作數(shù)值的符號(hào)。比如,將-2左移5位,會(huì)得到-64,而不是64。
6. 右移運(yùn)算符
(1)有符號(hào)右移操作符(>>)
有符號(hào)右移操作符(>>)會(huì)將數(shù)值的32位全部右移若干位(同時(shí)會(huì)保留正負(fù)號(hào))。正數(shù)左補(bǔ)0,負(fù)數(shù)左補(bǔ)1,右邊丟棄。操作數(shù)每右移一位,相當(dāng)于該數(shù)除以2。
例如:a = a >>2 就是將a的二進(jìn)制位右移2位,左補(bǔ)0 或者 左補(bǔ)1得看被移數(shù)是正還是負(fù)。
(2)無符號(hào)右移操作符(>>>)
無符號(hào)右移操作符(>>>)會(huì)將數(shù)值的32位全部右移。對(duì)于正數(shù),有符號(hào)右移操作符和無符號(hào)右移操作符的結(jié)果是一樣的。對(duì)于負(fù)數(shù)的操作,兩者就會(huì)有較大的差異。
無符號(hào)右移操作符將負(fù)數(shù)的二進(jìn)制表示當(dāng)成正數(shù)的二進(jìn)制表示來處理。所以,對(duì)負(fù)數(shù)進(jìn)行無符號(hào)右移操作之后就會(huì)變的特別大。
三、加減乘除操作符
1. 加法操作符(+)
這里說的加法操作符就是二元的加操作符了。二元加操作符用于計(jì)算數(shù)值操作或者拼接字符串操作。
1?+?1?????????????//?2 "1"?+?"2"?????????//?"12" "hello"?+?"world"?//?"helloworld"
在進(jìn)行加操作時(shí),如果兩個(gè)操作數(shù)都是數(shù)值或者都是字符串,那么執(zhí)行結(jié)果就分別是計(jì)算出來的數(shù)值和拼接好的字符串。除此之外,執(zhí)行結(jié)果都取決于類型轉(zhuǎn)化的結(jié)果:它會(huì)優(yōu)先進(jìn)行字符串拼接,只有操作數(shù)是字符串或者是可以轉(zhuǎn)化為字符串的對(duì)象,另一個(gè)操作數(shù)也會(huì)被轉(zhuǎn)化為字符串,并執(zhí)行拼接操作。只有任何操作數(shù)都不是字符串時(shí)才會(huì)執(zhí)行加法操作。
1?+?2?????????????//?3 "1"?+?"2"?????????//?"12" "1"?+?2???????????//?"12" 1?+?{}????????????//?"1[object?Object]" true?+?false??????//?1??布爾值會(huì)先轉(zhuǎn)為數(shù)字,再進(jìn)行運(yùn)算 1?+?null??????????//?1?null會(huì)轉(zhuǎn)化為0,再進(jìn)行計(jì)算 1?+?undefined?????//?NaN?undefined轉(zhuǎn)化為數(shù)字是NaN
需要注意加操作的順序:
let?a?=?1; let?b?=?2; let?c?=?"hello"?+?a?+?b;??//?"hello12"
這里,由于每次加法操作都是獨(dú)立完成的,第一次是字符串hello和數(shù)字a做加法操作,得到的結(jié)果是"hello1",第二次加法操作仍然是一個(gè)字符串加一個(gè)數(shù)字,所以最終結(jié)果是一個(gè)字符串。如果想讓a和b兩個(gè)數(shù)字相加,就需要加上括號(hào)。
除此之外,還需要注意以下特殊情況:
- 如果有一個(gè)操作數(shù)是NaN,則結(jié)果是NaN;
- 如果是Infinity加Infinity,則結(jié)果是Infinity;
- 如果是-Infinity加-Infinity,則結(jié)果是-Infinity;
- 如果是Infinity加-Infinity,則結(jié)果是NaN;
- 如果是+0加+0,則結(jié)果是+0;
- 如果是-0加-0,則結(jié)果是-0;
- 如果是+0加-0,則結(jié)果是+0。
2. 減法操作符(-)
減法操作和加法操作符類似, 但是減法操作符只能用于數(shù)值的計(jì)算,不能用于字符串的拼接。當(dāng)進(jìn)行減法操作時(shí),如果兩個(gè)操作數(shù)都是數(shù)值,就會(huì)直接進(jìn)行減法操作,如果有一個(gè)操作數(shù)是非數(shù)值,就會(huì)將其轉(zhuǎn)化為數(shù)值,再進(jìn)行減法操作。如果轉(zhuǎn)化結(jié)果為NaN,則運(yùn)算結(jié)果也是NaN。
3?-?1??????//?2 3?-?true???//?2 3?-?""?????//?3 3?-?null???//?3 NaN?-?1????//?NaN
需要注意以下特殊情況:
- 如果是Infinity減Infinity,則結(jié)果是NaN;
- 如果是-Infinity減-Infinity,則結(jié)果是NaN;
- 如果是Infinity減-Infinity,則結(jié)果是Infinity;
- 如果是-Infinity減Infinity,則結(jié)果是-Infinity;
- 如果是+0減+0,則結(jié)果是+0;
- 如果是-0減+0,則結(jié)果是-0;
- 如果是-0減-0,則結(jié)果是+0。
3. 乘法操作符(*)
乘法操作符用于計(jì)算兩個(gè)數(shù)的乘積。如果兩個(gè)操作數(shù)都是數(shù)值,則會(huì)執(zhí)行常規(guī)的乘法運(yùn)算。如果不是數(shù)值,會(huì)將其轉(zhuǎn)化為數(shù)值,在進(jìn)行乘法操作。
需要注意以下特殊情況:
- 如果有一個(gè)操作數(shù)是NaN,則結(jié)果是NaN;
- 如果Infinity與0相乘,則結(jié)果是NaN;
- 如果Infinity與非0數(shù)值相乘,則結(jié)果是Infinity或-Infinity,取決于有符號(hào)操作數(shù)的符號(hào);
- 如果Infinity與Infinity相乘,則結(jié)果是Infinity。
4. 除法操作符(/)
除法操作符用于計(jì)算一個(gè)操作數(shù)除以第二個(gè)操作數(shù)的商。如果兩個(gè)操作數(shù)都是數(shù)值,則會(huì)執(zhí)行常規(guī)的除法運(yùn)算。如果不是數(shù)值,會(huì)將其轉(zhuǎn)化為數(shù)值,在進(jìn)行除法操作。
需要注意以下特殊情況:
- 如果有一個(gè)操作數(shù)是NaN,則結(jié)果是NaN;
- 如果0除以0,則結(jié)果是NaN;
- 如果Infinity除以Infinity,則結(jié)果是Infinity。
- 如果是非零的有限數(shù)被零除,則結(jié)果是Infinity或-Infinity,取決于有符號(hào)操作數(shù)的符號(hào);
- 如果是Infinity被任何非零數(shù)值除,則結(jié)果是Infinity或-Infinity,取決于有符號(hào)操作數(shù)的符號(hào)。
5. 取余操作符(%)
取余操作符用于計(jì)算一個(gè)數(shù)除以第二個(gè)數(shù)的余數(shù)。計(jì)算規(guī)則和上述運(yùn)算符類似。
需要注意以下特殊情況:
- 如果被除數(shù)是無窮大值而除數(shù)是有限大的數(shù)值,則結(jié)果是NaN;
- 如果被除數(shù)是有限大的數(shù)值而除數(shù)是零,則結(jié)果是NaN;
- 如果是Infinity被Infinity除,則結(jié)果是NaN;
- 如果被除數(shù)是有限大的數(shù)值而除數(shù)是無窮大的數(shù)值,則結(jié)果是被除數(shù);
- 如果被除數(shù)是零,則結(jié)果是零。
6. 指數(shù)操作符(**)
在ECMAScript 7中新增了指數(shù)操作符(**),它的計(jì)算效果是Math.pow()是一樣的:
Math.pow(2,?10);????//?1024 2?**?10;????????????//?1024
指數(shù)運(yùn)算符和上面的加減乘除運(yùn)算符都有對(duì)應(yīng)的賦值操作運(yùn)算符:
let?a?=?2; a?**=?10; console.log(a);???//?1024
let?a?=?1; let?b?=?2; let?c?=?3; let?d?=?4; a?+=?1;?????//?2 b?-=?2;?????//?0 c?*=?3;?????//?9 d?/=?4;?????//?1
四、布爾操作符
在開發(fā)時(shí),布爾操作符是很有用的,可以精簡很多代碼,干掉很多多余的id-else語句,下面來看看常見的三種布爾操作符。
1. 邏輯非操作符(!)
邏輯非操作符可以用于JavaScript中的任何值,這個(gè)操作符使用返回布爾值。邏輯非操作符首先會(huì)將操作數(shù)轉(zhuǎn)化為布爾值,然后在對(duì)其取反。
邏輯非操作規(guī)則如下:
- 如果操作數(shù)是對(duì)象,則返回 false;
- 如果操作數(shù)是空字符串,則返回 true;
- 如果操作數(shù)是非空字符串,則返回 false;
- 如果操作數(shù)是數(shù)值0,則返回 true;
- 如果操作數(shù)是非0數(shù)值(包括 Infinity),則返回 false;
- 如果操作數(shù)是 null,則返回 true;
- 如果操作數(shù)是 NaN,則返回 true;
- 如果操作數(shù)是 undefined, 則返回 true.
邏輯非操作符也可以用于將任何值轉(zhuǎn)化為布爾值,同時(shí)使用兩個(gè)!,相當(dāng)于調(diào)用了Boolean()方法:
!!"blue"?//?true !!0;?????//?false !!NaN????//?false !!""?????//?false !!12345??//?true
2. 邏輯與操作符(&&)
邏輯與操作符的兩個(gè)操作數(shù)都為真時(shí),最終結(jié)果才會(huì)返回真。該運(yùn)算符可以用于任何類型的數(shù)據(jù)。如果有操作數(shù)不是布爾值,則結(jié)果并一定會(huì)返回布爾值,會(huì)遵循以下規(guī)則:
- 如果第一個(gè)操作數(shù)是對(duì)象,則返回第二個(gè)操作數(shù);
- 如果第二個(gè)操作數(shù)是對(duì)象,則只有在第一個(gè)操作數(shù)的求值結(jié)果為true的情況下才會(huì)返回該對(duì)象;
- 如果兩個(gè)操作數(shù)都是對(duì)象,則返回第二個(gè)操作數(shù);
- 如果第一個(gè)操作數(shù)是null,則返回null;
- 如果第一個(gè)操作數(shù)是NaN,則返回NaN;
- 如果第一個(gè)操作數(shù)是undefined,則返回undefined;
根據(jù)第二條規(guī)則,我們可以對(duì)我們項(xiàng)目代碼中的代碼進(jìn)行優(yōu)化:
if(data)?{ ??setData(data); } //?改寫后: data?&&?setData(data);
這里當(dāng)data為真時(shí),也就是存在時(shí),才會(huì)執(zhí)行setData方法,代碼就精簡了很多。
邏輯與操作符是一種短路操作符,只要第一個(gè)操作數(shù)為false,就不會(huì)繼續(xù)執(zhí)行運(yùn)算符后面的表達(dá)式,直接返回false。上面的data如果是不存在的,就會(huì)直接發(fā)生短路,不會(huì)繼續(xù)執(zhí)行后面的方法。
3. 邏輯或操作符(||)
邏輯或操作符和邏輯與操作符類似,不過只要兩個(gè)操作數(shù)中的一個(gè)為真,最終的結(jié)果就為真。該運(yùn)算符可以用于任何類型的數(shù)據(jù)。如果有操作數(shù)不是布爾值,則結(jié)果并一定會(huì)返回布爾值,會(huì)遵循以下規(guī)則:
- 如果第一個(gè)操作數(shù)是對(duì)象,則返回第一個(gè)操作對(duì)象;
- 如果第一個(gè)操作數(shù)的求值結(jié)果是false,則返回第二個(gè)操作數(shù);
- 如果兩個(gè)操作數(shù)都是對(duì)象,則返回第一個(gè)操作數(shù);
- 如果兩個(gè)操作數(shù)都是null,則返回null;
- 如果兩個(gè)數(shù)都是NaN,則返回NaN;
- 如果兩個(gè)數(shù)都是undefined,則返回undefined。
邏輯或操作符也是具有短路特性,如果第一個(gè)操作數(shù)為真,那么第二個(gè)操作數(shù)就不需要在進(jìn)行判斷了,會(huì)直接返回true。
可以利用這個(gè)特性給變量設(shè)置默認(rèn)值:
let?datas?=?data?||?{};
這里,如果data不存在,就會(huì)將datas賦值為第二個(gè)操作數(shù)(默認(rèn)值)。
五、比較操作符
1. 相等操作符
相等操作符包括四種:
- 等于(==)
- 不等于(!=)
- 全等(===)
- 不全等(!==)
JavaScript中的等于用兩個(gè)等號(hào)(==)表示,如果兩個(gè)操作數(shù)相等,那么就返回true。不等于和等于相反。在進(jìn)行比較時(shí),兩個(gè)操作數(shù)都會(huì)進(jìn)行強(qiáng)制類型轉(zhuǎn)換,在確實(shí)是否相等。其判斷規(guī)則如下:
1.首先會(huì)判斷兩者類型是否相同,相同的話就比較兩者的大?。?/p>
2.類型不相同的話,就會(huì)進(jìn)行類型轉(zhuǎn)換;
3.會(huì)先判斷是否在對(duì)比 null
和 undefined
,是的話就會(huì)返回 true
4.判斷兩者類型是否為 string
和 number
,是的話就會(huì)將字符串轉(zhuǎn)換為 number
1 == '1'
↓
1 == 1
5.判斷其中一方是否為 boolean
,是的話就會(huì)把 boolean
轉(zhuǎn)為 number
再進(jìn)行判斷
'1' == true
↓
'1' == 1
↓
1 == 1
6.判斷其中一方是否為 object
且另一方為 string
、number
或者 symbol
,是的話就會(huì)把 object
轉(zhuǎn)為原始類型再進(jìn)行判斷
'1' == { name: 'js' }
↓
'1' == '[object Object]'
其流程圖如下:
需要注意,如果其中一個(gè)操作數(shù)是NaN,相等運(yùn)算符會(huì)返回false,不相等運(yùn)算符會(huì)返回true。
對(duì)于不等于運(yùn)算符(!=),只有在強(qiáng)制類型轉(zhuǎn)化后不相等才會(huì)返回true。
對(duì)于全等運(yùn)算符(===),只有當(dāng)兩個(gè)操作數(shù)的數(shù)據(jù)類型和值都相等時(shí),才會(huì)返回true。它并不會(huì)進(jìn)行數(shù)據(jù)類型的轉(zhuǎn)化。
對(duì)于不全等運(yùn)算符(!==),只有兩個(gè)操作數(shù)在不進(jìn)行類型轉(zhuǎn)化的情況下是不相等的,才會(huì)返回true。
在平時(shí)的開發(fā)中,建議使用全等和不全等在做比較,這樣會(huì)更加嚴(yán)謹(jǐn),避免出現(xiàn)意料之外的結(jié)果。
2. 關(guān)系操作符
關(guān)系操作符包括四種:
- 小于(<)
- 大于(>)
- 小于等于(<=)
- 大于等于(>=)
這幾個(gè)操作符都會(huì)返回一個(gè)布爾值,他們操作時(shí)會(huì)遵循以下規(guī)則:
- 如果這兩個(gè)操作數(shù)都是數(shù)值,則執(zhí)行數(shù)值比較;
- 如果兩個(gè)操作數(shù)都是字符串,則比較兩個(gè)字符串對(duì)應(yīng)的字符編碼值;
- 如果一個(gè)操作數(shù)是數(shù)值,則將另一個(gè)操作數(shù)轉(zhuǎn)換為一個(gè)數(shù)值,然后執(zhí)行數(shù)值比較;
- 如果一個(gè)操作數(shù)是對(duì)象,則調(diào)用這個(gè)對(duì)象的valueOf()方法,并用得到的結(jié)果根據(jù)前面的規(guī)則執(zhí)行比較;
- 如果一個(gè)操作數(shù)是布爾值,則先將其轉(zhuǎn)換為數(shù)值,然后再執(zhí)行比較。
六、其他操作符
最后這一部分的一些操作符在平時(shí)的開發(fā)中就很實(shí)用了,下面來看看它們的用法吧。
1. 擴(kuò)展運(yùn)算符(...)
擴(kuò)展操作符(Spread operator)可以用來擴(kuò)展一個(gè)數(shù)組對(duì)象和字符串。它用三個(gè)點(diǎn)(…)表示,可以將可迭代對(duì)象轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列。
(1)用于展開數(shù)組:
const?a?=?[1,?2,?3], ??????b?=?[4,?5,?6]; const?c?=?[...a]???????//?[1,?2,?3] const?d?=?[...a,?...b]?//?[1,?2,?3,?4,?5,?6] const?e?=?[...a,?4,?5]?//?[1,?2,?3,?4,?5]
(2)將類數(shù)組對(duì)象變成數(shù)組:
const?list?=?document.getElementsByTagName('a'); const?arr?=?[..list];
(3)用于展開對(duì)象:
const?obj1?=?{?a:?1,?b:?2?}; const?obj2?=?{?c:?3,?d:?4?}; const?merged?=?{?...obj1,?...obj2?};??//?{?a:?1,?b:?2,?c:?3,?d:?4?}
需要注意,如果合并時(shí)的多個(gè)對(duì)象有相同屬性,則后面的對(duì)象的會(huì)覆蓋前面對(duì)象的屬性。
(4)用于展開字符串
const?str?=?"hello"; [...str]??//?["h",?"e",?"l",?"l",?"o"]
(5)用于函數(shù)傳參
const?f?=?(foo,?bar)?=>?{} const?a?=?[1,?2] f(...a) const?numbers?=?[1,?2,?3,?4,?5] const?sum?=?(a,?b,?c,?d,?e)?=>?a?+?b?+?c?+?d?+?e const?sum?=?sum(...numbers)
(6)用于具有 Iterator 接口的對(duì)象
具有 Iterator 接口的對(duì)象 Map 和 Set 結(jié)構(gòu),Generator 函數(shù),可以使用展開操作符:
const?s?=?new?Set(); s.add(1); s.add(2); const?arr?=?[...s]//?[1,2] function?*?gen()?{ ??yield?1; ??yield?2; ??yield?3; } const?arr?=?[...gen()]?//?1,2,3
如果是map,會(huì)把每個(gè)key 和 value 轉(zhuǎn)成一個(gè)數(shù)組:
const?m?=?new?Map(); m.set(1,1) m.set(2,2) const?arr?=?[...m]??//?[[1,1],[2,2]]
注意 ,對(duì)象不是一個(gè)Iterator對(duì)象。
2. 條件操作符(?:)
這里的條件運(yùn)算符實(shí)際上就是我們常說的三元表達(dá)式??匆粋€(gè)例子:
let?res?=?num1?>?num2???num1?:?num2;
這里,將num1和num2中的最大值賦值給了res。
使用條件表達(dá)式可以代替很多if-else,使得代碼很簡潔。在React的項(xiàng)目中,我個(gè)人就經(jīng)常使用條件操作符來做組件的條件渲染。當(dāng)然如果判斷的層數(shù)過多,感覺代碼就有些難讀懂了。(React-Router源碼中就有嵌套了六七層條件操作符的地方,很難理解...)
3. 賦值操作符
其實(shí)賦值操作符有很多種,包括簡單的賦值操作符(=),以及一些復(fù)合賦值操作符:
- 乘賦值操作符:*=
- 除賦值操作符:/=
- 模賦值操作符:%=
- 加賦值操作符:+=
- 減賦值操作符:-=
- 左移操作符: <<=
- 有符號(hào)右移賦值操作符:>>=
- 無符號(hào)右移賦值操作符:>>>=
這些僅僅是他們對(duì)應(yīng)的簡寫形式,并不會(huì)產(chǎn)生其他影響。
4. in操作符
in操作符可以用來判斷一個(gè)屬性是否屬于一個(gè)對(duì)象,它的返回值是一個(gè)布爾值:
const?author?=?{ ??name:?"CUGGZ", ??age:?18 } "height"?in?author;??//?false "age"?in?author;?????//?true
還可以用來判斷一個(gè)屬性是否屬于對(duì)象原型鏈的一部分:
let?arr?=?["hello",?"jue",?"jin"]; "length"?in?arr;???//?true
5. delete操作符
delete 操作符用于刪除對(duì)象的某個(gè)屬性或者數(shù)組元素。對(duì)于引用類型的值,它也是刪除對(duì)象屬性的本身,不會(huì)刪除屬性指向的對(duì)象。
const?o?=?{}; const?a?=?{?x:?10?}; o.a?=?a; delete?o.a;?//?o.a屬性被刪除 console.log(o.a);?//?undefined console.log(a.x);?//?10,?因?yàn)閧?x:?10?}?對(duì)象依然被?a?引用,所以不會(huì)被回收
需要注意:
- 原型中聲明的屬性和對(duì)象自帶的屬性無法被刪除;
- 通過var聲明的變量和通過function聲明的函數(shù)擁有dontdelete特性,是不能被刪除。
6. instanceof操作符
instanceof運(yùn)算符用來判斷一個(gè)構(gòu)造函數(shù)的prototype屬性所指向的對(duì)象是否存在另外一個(gè)要檢測對(duì)象的原型鏈上。
console.log(2?instanceof?Number);????????????????????//?false console.log(true?instanceof?Boolean);????????????????//?false? console.log('str'?instanceof?String);????????????????//?false? ? console.log([]?instanceof?Array);????????????????????//?true console.log(function(){}?instanceof?Function);???????//?true console.log({}?instanceof?Object);???????????????????//?true
可以看到,instanceof只能正確判斷引用數(shù)據(jù)類型,而不能判斷基本數(shù)據(jù)類型。instanceof運(yùn)算符可以用來測試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性。
可以簡單來實(shí)現(xiàn)一下 instanceof 操作符:
function?myInstanceof(left,?right)?{ ??//?獲取對(duì)象的原型 ??let?proto?=?Object.getPrototypeOf(left) ??//?獲取構(gòu)造函數(shù)的?prototype?對(duì)象 ??let?prototype?=?right.prototype;? ? ??//?判斷構(gòu)造函數(shù)的?prototype?對(duì)象是否在對(duì)象的原型鏈上 ??while?(true)?{ ????if?(!proto)?return?false; ????if?(proto?===?prototype)?return?true; ????//?如果沒有找到,就繼續(xù)從其原型上找,Object.getPrototypeOf方法用來獲取指定對(duì)象的原型 ????proto?=?Object.getPrototypeOf(proto); ??} }
7. typeof操作符
typeof是一元運(yùn)算符,它的返回值是一個(gè)字符串,它是操作數(shù)的類型,JavaScript常見數(shù)據(jù)對(duì)應(yīng)的類型如下:
x | typeof |
---|---|
undefined | undefined |
null | object |
true或false | boolean |
數(shù)值或NaN | number |
BigInt | bigInt |
字符串 | string |
symbol | symbol |
函數(shù) | function |
非函數(shù)對(duì)象 | object |
typeof?2???????????????//?number typeof?true????????????//?boolean typeof?'str'???????????//?string typeof?[]??????????????//?object???? typeof?function(){}????//?function typeof?{}??????????????//?object typeof?undefined???????//?undefined typeof?null????????????//?object
那這里為什么 typeof null 的結(jié)果是Object呢?
在 JavaScript 第一個(gè)版本中,所有值都存儲(chǔ)在 32 位的單元中,每個(gè)單元包含一個(gè)小的 類型標(biāo)簽(1-3 bits) 以及當(dāng)前要存儲(chǔ)值的真實(shí)數(shù)據(jù)。類型標(biāo)簽存儲(chǔ)在每個(gè)單元的低位中,共有五種數(shù)據(jù)類型:
000: object - 當(dāng)前存儲(chǔ)的數(shù)據(jù)指向一個(gè)對(duì)象。
1: int - 當(dāng)前存儲(chǔ)的數(shù)據(jù)是一個(gè) 31 位的有符號(hào)整數(shù)。
010: double - 當(dāng)前存儲(chǔ)的數(shù)據(jù)指向一個(gè)雙精度的浮點(diǎn)數(shù)。
100: string - 當(dāng)前存儲(chǔ)的數(shù)據(jù)指向一個(gè)字符串。
110: boolean - 當(dāng)前存儲(chǔ)的數(shù)據(jù)是布爾值。
如果最低位是 1,則類型標(biāo)簽標(biāo)志位的長度只有一位;如果最低位是 0,則類型標(biāo)簽標(biāo)志位的長度占三位,為存儲(chǔ)其他四種數(shù)據(jù)類型提供了額外兩個(gè) bit 的長度。
有兩種特殊數(shù)據(jù)類型:
- undefined的值是 (-2)30(一個(gè)超出整數(shù)范圍的數(shù)字);
- null 的值是機(jī)器碼 NULL 指針(null 指針的值全是 0)
那也就是說null的類型標(biāo)簽也是000,和Object的類型標(biāo)簽一樣,所以會(huì)被判定為Object。
8. 空值合并操作符(??)
在編寫代碼時(shí),如果某個(gè)屬性不為 null 和 undefined,那么就獲取該屬性,如果該屬性為 null 或 undefined,則取一個(gè)默認(rèn)值:
const?name?=?dogName???dogName?:?'default';?
可以通過 || 來簡化:
const?name?=??dogName?||?'default';?
但是 || 的寫法存在一定的缺陷,當(dāng) dogName 為 0 或 false 的時(shí)候也會(huì)走到 default 的邏輯。所以 ES2020 引入了 ?? 運(yùn)算符。只有 ?? 左邊為 null 或 undefined時(shí)才返回右邊的值:
const?dogName?=?false;? const?name?=??dogName????'default';??//?name?=?false;
9. 可選鏈操作符(?.)
在開發(fā)過程中,我們可能需要獲取深層次屬性,例如 system.user.addr.province.name。但在獲取 name 這個(gè)屬性前需要一步步的判斷前面的屬性是否存在,否則并會(huì)報(bào)錯(cuò):
const?name?=?(system?&&?system.user?&&?system.user.addr?&&?system.user.addr.province?&&?system.user.addr.province.name)?||?'default';
為了簡化上述過程,ES2020 引入了「鏈判斷運(yùn)算符」?.,可選鏈操作符( ?. )允許讀取位于連接對(duì)象鏈深處的屬性的值,而不必明確驗(yàn)證鏈中的每個(gè)引用是否有效。?. 操作符的功能類似于 . 鏈?zhǔn)讲僮鞣?,不同之處在于,在引用為null 或 undefined 的情況下不會(huì)引起錯(cuò)誤,該表達(dá)式短路返回值是 undefined。與函數(shù)調(diào)用一起使用時(shí),如果給定的函數(shù)不存在,則返回 undefined。
const?name?=?system?.user?.addr?.province?.name?||?'default';
當(dāng)嘗試訪問可能不存在的對(duì)象屬性時(shí),可選鏈操作符將會(huì)使表達(dá)式更短、更簡明。在探索一個(gè)對(duì)象的內(nèi)容時(shí),如果不能確定哪些屬性必定存在,可選鏈操作符也是很有幫助的。
可選鏈有以下三種形式:
a?.[x] //?等同于 a?==?null???undefined?:?a[x] a?.b() //?等同于 a?==?null???undefined?:?a.b() a?.() //?等同于 a?==?null???undefined?:?a()
10. 逗號(hào)操作符(,)
逗號(hào)操作符也沒啥好說的,當(dāng)同時(shí)聲明多個(gè)變量時(shí)會(huì)用到:
let?a?=?1,?b?=?2,?c?=?3;
還有一種使用場景就是有多個(gè)循環(huán)變量的 for 循環(huán)中:
for(let?i?=?0,?j?=?10;?i?<?j;?i++,?j--){ ??console.log(i?+?j); }
11. void操作符(void)
void 是一元運(yùn)算符,它可以出現(xiàn)在任意類型的操作數(shù)之前執(zhí)行操作數(shù),會(huì)忽略操作數(shù)的返回值,返回一個(gè) undefined。void 常用于 HTML 腳本中執(zhí)行 JavaScript 表達(dá)式,但不需要返回表達(dá)式的計(jì)算結(jié)果。比如對(duì)于鏈接標(biāo)簽,我們并不想讓它發(fā)生跳轉(zhuǎn),就可以設(shè)置href="javascript:void(0)
。
在下面代碼中,使用 void 運(yùn)算符讓表達(dá)式返回 undefined:
let?a?=?b?=?c?=?2;??//?定義并初始化變量的值 d?=?void?(a?-=?(b?*=?(c?+=?5)));??//?執(zhí)行void運(yùn)算符,并把返回值賦予變量d console.log(a);??//?-12 console.log(b);??//?14 console.log(c);??//?7 console.log(d);??//?undefined
由于 void 運(yùn)算符的優(yōu)先級(jí)比較高,高于普通運(yùn)算符的優(yōu)先級(jí),所以在使用時(shí)應(yīng)該使用小括號(hào)明確 void 運(yùn)算符操作的操作數(shù),避免引發(fā)錯(cuò)誤。
到此這篇關(guān)于JavaScript中強(qiáng)大的操作符使用詳解的文章就介紹到這了,更多相關(guān)JavaScript操作符內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js簡單實(shí)現(xiàn)點(diǎn)擊左右運(yùn)動(dòng)的方法
這篇文章主要介紹了js簡單實(shí)現(xiàn)點(diǎn)擊左右運(yùn)動(dòng)的方法,實(shí)例分析了javascript實(shí)現(xiàn)左右運(yùn)動(dòng)的相關(guān)要點(diǎn)與技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04D3.js 從P元素的創(chuàng)建開始(顯示可加載數(shù)據(jù))
D3是一個(gè)基于數(shù)據(jù)操作的可視化js庫,認(rèn)識(shí)d3,就從最基礎(chǔ)的顯示可加載數(shù)據(jù)談起,需要的朋友可以參考下2014-10-10html+css+js實(shí)現(xiàn)別踩白板小游戲
大家好,本篇文章主要的講的是html+css+js實(shí)現(xiàn)別踩白板小游戲,感興趣的同學(xué)趕快來看一看吧,覺得不錯(cuò)的話可以收藏一下哦,方便下次瀏覽2021-11-11JS實(shí)現(xiàn)區(qū)分中英文并統(tǒng)計(jì)字符個(gè)數(shù)的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)區(qū)分中英文并統(tǒng)計(jì)字符個(gè)數(shù)的方法,涉及JavaScript事件響應(yīng)、正則匹配及數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2018-06-06