W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
我們從學(xué)校里了解到過(guò)很多運(yùn)算符,比如說(shuō)加號(hào) ?+
?、乘號(hào) ?*
?、減號(hào) ?-
? 等。
在本章中,我們將從簡(jiǎn)單的運(yùn)算符開始,然后著重介紹 JavaScript 特有的方面,這些是在學(xué)校中學(xué)習(xí)的數(shù)學(xué)運(yùn)算所沒(méi)有涵蓋的。
在正式開始前,我們先簡(jiǎn)單瀏覽一下常用術(shù)語(yǔ)。
5 * 2
?,有兩個(gè)運(yùn)算元:左運(yùn)算元 ?5
? 和右運(yùn)算元 ?2
?。有時(shí)候人們也稱其為“參數(shù)”而不是“運(yùn)算元”。-
?,它的作用是對(duì)數(shù)字進(jìn)行正負(fù)轉(zhuǎn)換:let x = 1;
x = -x;
alert( x ); // -1,一元負(fù)號(hào)運(yùn)算符生效
let x = 1, y = 3;
alert( y - x ); // 2,二元運(yùn)算符減號(hào)做減運(yùn)算
嚴(yán)格地說(shuō),在上面的示例中,我們使用一個(gè)相同的符號(hào)表征了兩個(gè)不同的運(yùn)算符:負(fù)號(hào)運(yùn)算符,即反轉(zhuǎn)符號(hào)的一元運(yùn)算符,減法運(yùn)算符,是從另一個(gè)數(shù)減去一個(gè)數(shù)的二元運(yùn)算符。
支持以下數(shù)學(xué)運(yùn)算:
+
?,-
?,*
?,/
?,%
?,**
?.前四個(gè)都很簡(jiǎn)單,而 ?%
? 和 ?**
? 則需要說(shuō)一說(shuō)。
取余運(yùn)算符是 %
,盡管它看起來(lái)很像百分?jǐn)?shù),但實(shí)際并無(wú)關(guān)聯(lián)。
a % b
的結(jié)果是 a
整除 b
的 余數(shù))。
例如:
alert( 5 % 2 ); // 1,5 除以 2 的余數(shù)
alert( 8 % 3 ); // 2,8 除以 3 的余數(shù)
求冪運(yùn)算 a ** b
將 a
提升至 a
的 b
次冪。
在數(shù)學(xué)運(yùn)算中我們將其表示為 ab。
例如:
alert( 2 ** 2 ); // 22 = 4
alert( 2 ** 3 ); // 23 = 8
alert( 2 ** 4 ); // 2? = 16
就像在數(shù)學(xué)運(yùn)算中一樣,冪運(yùn)算也適用于非整數(shù)。
例如,平方根是指數(shù)為 ? 的冪運(yùn)算:
alert( 4 ** (1/2) ); // 2(1/2 次方與平方根相同)
alert( 8 ** (1/3) ); // 2(1/3 次方與立方根相同)
我們來(lái)看一些學(xué)校算術(shù)未涉及的 JavaScript 運(yùn)算符的特性。
通常,加號(hào) +
用于求和。
但是如果加號(hào) +
被應(yīng)用于字符串,它將合并(連接)各個(gè)字符串:
let s = "my" + "string";
alert(s); // mystring
注意:只要任意一個(gè)運(yùn)算元是字符串,那么另一個(gè)運(yùn)算元也將被轉(zhuǎn)化為字符串。
舉個(gè)例子:
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
你看,第一個(gè)運(yùn)算元和第二個(gè)運(yùn)算元,哪個(gè)是字符串并不重要。
下面是一個(gè)更復(fù)雜的例子:
alert(2 + 2 + '1' ); // "41",不是 "221"
在這里,運(yùn)算符是按順序工作。第一個(gè) +
將兩個(gè)數(shù)字相加,所以返回 4
,然后下一個(gè) +
將字符串 1
加入其中,所以就是 4 + '1' = '41'
。
alert('1' + 2 + 2); // "122",不是 "14"
這里,第一個(gè)操作數(shù)是一個(gè)字符串,所以編譯器將其他兩個(gè)操作數(shù)也視為了字符串。2
被與 '1'
連接到了一起,也就是像 '1' + 2 = "12"
然后 "12" + 2 = "122"
這樣。
二元 +
是唯一一個(gè)以這種方式支持字符串的運(yùn)算符。其他算術(shù)運(yùn)算符只對(duì)數(shù)字起作用,并且總是將其運(yùn)算元轉(zhuǎn)換為數(shù)字。
下面是減法和除法運(yùn)算的示例:
alert( 6 - '2' ); // 4,將 '2' 轉(zhuǎn)換為數(shù)字
alert( '6' / '2' ); // 3,將兩個(gè)運(yùn)算元都轉(zhuǎn)換為數(shù)字
加號(hào) +
有兩種形式。一種是上面我們剛剛討論的二元運(yùn)算符,還有一種是一元運(yùn)算符。
一元運(yùn)算符加號(hào),或者說(shuō),加號(hào) +
應(yīng)用于單個(gè)值,對(duì)數(shù)字沒(méi)有任何作用。但是如果運(yùn)算元不是數(shù)字,加號(hào) +
則會(huì)將其轉(zhuǎn)化為數(shù)字。
例如:
// 對(duì)數(shù)字無(wú)效
let x = 1;
alert( +x ); // 1
let y = -2;
alert( +y ); // -2
// 轉(zhuǎn)化非數(shù)字
alert( +true ); // 1
alert( +"" ); // 0
它的效果和 Number(...)
相同,但是更加簡(jiǎn)短。
我們經(jīng)常會(huì)有將字符串轉(zhuǎn)化為數(shù)字的需求。比如,如果我們正在從 HTML 表單中取值,通常得到的都是字符串。如果我們想對(duì)它們求和,該怎么辦?
二元運(yùn)算符加號(hào)會(huì)把它們合并成字符串:
let apples = "2";
let oranges = "3";
alert( apples + oranges ); // "23",二元運(yùn)算符加號(hào)合并字符串
如果我們想把它們當(dāng)做數(shù)字對(duì)待,我們需要轉(zhuǎn)化它們,然后再求和:
let apples = "2";
let oranges = "3";
// 在二元運(yùn)算符加號(hào)起作用之前,所有的值都被轉(zhuǎn)化為了數(shù)字
alert( +apples + +oranges ); // 5
// 更長(zhǎng)的寫法
// alert( Number(apples) + Number(oranges) ); // 5
從一個(gè)數(shù)學(xué)家的視角來(lái)看,大量的加號(hào)可能很奇怪。但是從一個(gè)程序員的視角,沒(méi)什么好奇怪的:一元運(yùn)算符加號(hào)首先起作用,它們將字符串轉(zhuǎn)為數(shù)字,然后二元運(yùn)算符加號(hào)對(duì)它們進(jìn)行求和。
為什么一元運(yùn)算符先于二元運(yùn)算符作用于運(yùn)算元?接下去我們將討論到,這是由于它們擁有 更高的優(yōu)先級(jí)。
如果一個(gè)表達(dá)式擁有超過(guò)一個(gè)運(yùn)算符,執(zhí)行的順序則由 優(yōu)先級(jí) 決定。換句話說(shuō),所有的運(yùn)算符中都隱含著優(yōu)先級(jí)順序。
從小學(xué)開始,我們就知道在表達(dá)式 1 + 2 * 2
中,乘法先于加法計(jì)算。這就是一個(gè)優(yōu)先級(jí)問(wèn)題。乘法比加法擁有 更高的優(yōu)先級(jí)。
圓括號(hào)擁有最高優(yōu)先級(jí),所以如果我們對(duì)現(xiàn)有的運(yùn)算順序不滿意,我們可以使用圓括號(hào)來(lái)修改運(yùn)算順序,就像這樣:(1 + 2) * 2
。
在 JavaScript 中有眾多運(yùn)算符。每個(gè)運(yùn)算符都有對(duì)應(yīng)的優(yōu)先級(jí)數(shù)字。數(shù)字越大,越先執(zhí)行。如果優(yōu)先級(jí)相同,則按照由左至右的順序執(zhí)行。
這是一個(gè)摘抄自 Mozilla 的 優(yōu)先級(jí)表(你沒(méi)有必要把這全記住,但要記住一元運(yùn)算符優(yōu)先級(jí)高于二元運(yùn)算符):
優(yōu)先級(jí) | 名稱 | 符號(hào) |
---|---|---|
… | … | … |
15 | 一元加號(hào) | +
|
15 | 一元負(fù)號(hào) | -
|
14 | 求冪 | **
|
13 | 乘號(hào) | *
|
13 | 除號(hào) | /
|
12 | 加號(hào) | +
|
12 | 減號(hào) | -
|
… | … | … |
2 | 賦值符 | =
|
… | … | … |
我們可以看到,“一元加號(hào)運(yùn)算符”的優(yōu)先級(jí)是 15
,高于“二元加號(hào)運(yùn)算符”的優(yōu)先級(jí) 12
。這也是為什么表達(dá)式 "+apples + +oranges"
中的一元加號(hào)先生效,然后才是二元加法。
我們知道賦值符號(hào) =
也是一個(gè)運(yùn)算符。從優(yōu)先級(jí)表中可以看到它的優(yōu)先級(jí)非常低,只有 2
。
這也是為什么,當(dāng)我們賦值時(shí),比如 x = 2 * 2 + 1
,所有的計(jì)算先執(zhí)行,然后 =
才執(zhí)行,將計(jì)算結(jié)果存儲(chǔ)到 x
。
let x = 2 * 2 + 1;
alert( x ); // 5
=
是一個(gè)運(yùn)算符,而不是一個(gè)有著“魔法”作用的語(yǔ)言結(jié)構(gòu)。
在 JavaScript 中,所有運(yùn)算符都會(huì)返回一個(gè)值。這對(duì)于 +
和 -
來(lái)說(shuō)是顯而易見的,但對(duì)于 =
來(lái)說(shuō)也是如此。
語(yǔ)句 x = value
將值 value
寫入 x
然后返回 value。
下面是一個(gè)在復(fù)雜語(yǔ)句中使用賦值的例子:
let a = 1;
let b = 2;
let c = 3 - (a = b + 1);
alert( a ); // 3
alert( c ); // 0
上面這個(gè)例子,(a = b + 1)
的結(jié)果是賦給 a
的值(也就是 3
)。然后該值被用于進(jìn)一步的運(yùn)算。
有趣的代碼,不是嗎?我們應(yīng)該了解它的工作原理,因?yàn)橛袝r(shí)我們會(huì)在 JavaScript 庫(kù)中看到它。
不過(guò),請(qǐng)不要寫這樣的代碼。這樣的技巧絕對(duì)不會(huì)使代碼變得更清晰或可讀。
另一個(gè)有趣的特性是鏈?zhǔn)劫x值:
let a, b, c;
a = b = c = 2 + 2;
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4
鏈?zhǔn)劫x值從右到左進(jìn)行計(jì)算。首先,對(duì)最右邊的表達(dá)式 2 + 2
求值,然后將其賦給左邊的變量:c
、b
和 a
。最后,所有的變量共享一個(gè)值。
同樣,出于可讀性,最好將這種代碼分成幾行:
c = 2 + 2;
b = c;
a = c;
這樣可讀性更強(qiáng),尤其是在快速瀏覽代碼的時(shí)候。
我們經(jīng)常需要對(duì)一個(gè)變量做運(yùn)算,并將新的結(jié)果存儲(chǔ)在同一個(gè)變量中。
例如:
let n = 2;
n = n + 5;
n = n * 2;
可以使用運(yùn)算符 +=
和 *=
來(lái)縮寫這種表示。
let n = 2;
n += 5; // 現(xiàn)在 n = 7(等同于 n = n + 5)
n *= 2; // 現(xiàn)在 n = 14(等同于 n = n * 2)
alert( n ); // 14
所有算術(shù)和位運(yùn)算符都有簡(jiǎn)短的“修改并賦值”運(yùn)算符:/=
和 -=
等。
這類運(yùn)算符的優(yōu)先級(jí)與普通賦值運(yùn)算符的優(yōu)先級(jí)相同,所以它們?cè)诖蠖鄶?shù)其他運(yùn)算之后執(zhí)行:
let n = 2;
n *= 3 + 5;
alert( n ); // 16 (右邊部分先被計(jì)算,等同于 n *= 8)
對(duì)一個(gè)數(shù)進(jìn)行加一、減一是最常見的數(shù)學(xué)運(yùn)算符之一。
所以,對(duì)此有一些專門的運(yùn)算符:
++
? 將變量與 1 相加:let counter = 2;
counter++; // 和 counter = counter + 1 效果一樣,但是更簡(jiǎn)潔
alert( counter ); // 3
--
將變量與 1 相減:let counter = 2;
counter--; // 和 counter = counter - 1 效果一樣,但是更簡(jiǎn)潔
alert( counter ); // 1
重要:
自增/自減只能應(yīng)用于變量。試一下,將其應(yīng)用于數(shù)值(比如
5++
)則會(huì)報(bào)錯(cuò)。
運(yùn)算符 ++
和 --
可以置于變量前,也可以置于變量后。
counter++
?。++counter
?。兩者都做同一件事:將變量 counter
與 1
相加。
那么它們有區(qū)別嗎?有,但只有當(dāng)我們使用 ++/--
的返回值時(shí)才能看到區(qū)別。
詳細(xì)點(diǎn)說(shuō)。我們知道,所有的運(yùn)算符都有返回值。自增/自減也不例外。前置形式返回一個(gè)新的值,但后置返回原來(lái)的值(做加法/減法之前的值)。
為了直觀看到區(qū)別,看下面的例子:
let counter = 1;
let a = ++counter; // (*)
alert(a); // 2
(*)
所在的行是前置形式 ++counter
,對(duì) counter
做自增運(yùn)算,返回的是新的值 2
。因此 alert
顯示的是 2
。
下面讓我們看看后置形式:
let counter = 1;
let a = counter++; // (*) 將 ++counter 改為 counter++
alert(a); // 1
(*)
所在的行是后置形式 counter++
,它同樣對(duì) counter
做加法,但是返回的是 舊值(做加法之前的值)。因此 alert
顯示的是 1
。
總結(jié):
let counter = 0;
counter++;
++counter;
alert( counter ); // 2,以上兩行作用相同
let counter = 0;
alert( ++counter ); // 1
let counter = 0;
alert( counter++ ); // 0
自增/自減和其它運(yùn)算符的對(duì)比
++/--
運(yùn)算符同樣可以在表達(dá)式內(nèi)部使用。它們的優(yōu)先級(jí)比絕大部分的算數(shù)運(yùn)算符要高。
舉個(gè)例子:
let counter = 1; alert( 2 * ++counter ); // 4
與下方例子對(duì)比:
let counter = 1; alert( 2 * counter++ ); // 2,因?yàn)?counter++ 返回的是“舊值”
盡管從技術(shù)層面上來(lái)說(shuō)可行,但是這樣的寫法會(huì)降低代碼的可閱讀性。在一行上做多個(gè)操作 —— 這樣并不好。
當(dāng)閱讀代碼時(shí),快速的視覺(jué)“縱向”掃描會(huì)很容易漏掉
counter++
,這樣的自增操作并不明顯。
我們建議用“一行一個(gè)行為”的模式:
let counter = 1; alert( 2 * counter ); counter++;
位運(yùn)算符把運(yùn)算元當(dāng)做 32 位整數(shù),并在它們的二進(jìn)制表現(xiàn)形式上操作。
這些運(yùn)算符不是 JavaScript 特有的。大部分的編程語(yǔ)言都支持這些運(yùn)算符。
下面是位運(yùn)算符:
&
? )|
? )^
? )~
? )<<
? )>>
? )>>>
? )這些運(yùn)算符很少被使用,一般是我們需要在最低級(jí)別(位)上操作數(shù)字時(shí)才使用。我們不會(huì)很快用到這些運(yùn)算符,因?yàn)樵?Web 開發(fā)中很少使用它們,但在某些特殊領(lǐng)域中,例如密碼學(xué),它們很有用。當(dāng)你需要了解它們的時(shí)候,可以閱讀 MDN 上的 位操作符 章節(jié)。
逗號(hào)運(yùn)算符 ,
是最少見最不常使用的運(yùn)算符之一。有時(shí)候它會(huì)被用來(lái)寫更簡(jiǎn)短的代碼,因此為了能夠理解代碼,我們需要了解它。
逗號(hào)運(yùn)算符能讓我們處理多個(gè)語(yǔ)句,使用 ,
將它們分開。每個(gè)語(yǔ)句都運(yùn)行了,但是只有最后的語(yǔ)句的結(jié)果會(huì)被返回。
舉個(gè)例子:
let a = (1 + 2, 3 + 4);
alert( a ); // 7(3 + 4 的結(jié)果)
這里,第一個(gè)語(yǔ)句 1 + 2
運(yùn)行了,但是它的結(jié)果被丟棄了。隨后計(jì)算 3 + 4
,并且該計(jì)算結(jié)果被返回。
逗號(hào)運(yùn)算符的優(yōu)先級(jí)非常低
請(qǐng)注意逗號(hào)運(yùn)算符的優(yōu)先級(jí)非常低,比
=
還要低,因此上面你的例子中圓括號(hào)非常重要。
如果沒(méi)有圓括號(hào):
a = 1 + 2, 3 + 4
會(huì)先執(zhí)行+
,將數(shù)值相加得到a = 3, 7
,然后賦值運(yùn)算符=
執(zhí)行a = 3
,然后逗號(hào)之后的數(shù)值7
不會(huì)再執(zhí)行,它被忽略掉了。相當(dāng)于(a = 1 + 2), 3 + 4
。
為什么我們需要這樣一個(gè)運(yùn)算符,它只返回最后一個(gè)值呢?
有時(shí)候,人們會(huì)使用它把幾個(gè)行為放在一行上來(lái)進(jìn)行復(fù)雜的運(yùn)算。
舉個(gè)例子:
// 一行上有三個(gè)運(yùn)算符
for (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
這樣的技巧在許多 JavaScript 框架中都有使用,這也是為什么我們提到它。但是通常它并不能提升代碼的可讀性,使用它之前,我們要想清楚。
重要程度: 5
以下代碼中變量 a
、b
、c
、d
的最終值分別是多少?
let a = 1, b = 1;
let c = ++a; // ?
let d = b++; // ?
答案如下:
- ?
a = 2
?- ?
b = 2
?- ?
c = 2
?- ?
d = 1
?let a = 1, b = 1; alert( ++a ); // 2,前置運(yùn)算符返回最新值 alert( b++ ); // 1,后置運(yùn)算符返回舊值 alert( a ); // 2,自增一次 alert( b ); // 2,自增一次
重要程度: 3
下面這段代碼運(yùn)行完成后,代碼中的 a
和 x
的值是多少?
let a = 2;
let x = 1 + (a *= 2);
答案如下:
- ?
a = 4
?(乘以 2)- ?
x = 5
?(相當(dāng)于計(jì)算 1 + 4)
重要程度: 5
下面這些表達(dá)式的結(jié)果是什么?
"" + 1 + 0
"" - 1 + 0
true + false
6 / "3"
"2" * "3"
4 + 5 + "px"
"$" + 4 + 5
"4" - 2
"4px" - 2
" -9 " + 5
" -9 " - 5
null + 1
undefined + 1
" \t \n" - 2
好好思考一下,把它們寫下來(lái)然后和答案比較一下。
"" + 1 + 0 = "10" // (1)
"" - 1 + 0 = -1 // (2)
true + false = 1
6 / "3" = 2
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
" -9 " + 5 = " -9 5" // (3)
" -9 " - 5 = -14 // (4)
null + 1 = 1 // (5)
undefined + 1 = NaN // (6)
" \t \n" - 2 = -2 // (7)
"" + 1
?,首先會(huì)將數(shù)字 ?1
? 轉(zhuǎn)換為一個(gè)字符串:?"" + 1 = "1"
?,然后我們得到 ?"1" + 0
?,再次應(yīng)用同樣的規(guī)則得到最終的結(jié)果。-
?(像大多數(shù)數(shù)學(xué)運(yùn)算一樣)只能用于數(shù)字,它會(huì)使空字符串 ?""
? 轉(zhuǎn)換為 ?0
?。5
? 加到字符串之后。" -9 "
? 轉(zhuǎn)換為數(shù)字 ?-9
?(忽略了字符串首尾的空格)。null
?經(jīng)過(guò)數(shù)字轉(zhuǎn)換之后會(huì)變?yōu)?nbsp;?0
?。undefined
?經(jīng)過(guò)數(shù)字轉(zhuǎn)換之后會(huì)變?yōu)?nbsp;?NaN
?。\t
?、?\n
? 以及它們之間的“常規(guī)”空格。因此,類似于空字符串,所以會(huì)變?yōu)?nbsp;?0
?。重要程度: 5
這里有一段代碼,要求用戶輸入兩個(gè)數(shù)字并顯示它們的總和。
它的運(yùn)行結(jié)果不正確。下面例子中的輸出是 12
(對(duì)于默認(rèn)的 prompt 的值)。
為什么會(huì)這樣?修正它。結(jié)果應(yīng)該是 3
。
let a = prompt("First number?", 1);
let b = prompt("Second number?", 2);
alert(a + b); // 12
原因是 prompt 以字符串的形式返回用戶的輸入。
所以變量的值分別為
"1"
和"2"
。
let a = "1"; // prompt("First number?", 1); let b = "2"; // prompt("Second number?", 2); alert(a + b); // 12
我們應(yīng)該做的是,在
+
之前將字符串轉(zhuǎn)換為數(shù)字。例如,使用Number()
或在prompt
前加+
。
例如,就在
prompt
之前加+
:
let a = +prompt("First number?", 1); let b = +prompt("Second number?", 2); alert(a + b); // 3
或在
alert
中:
let a = prompt("First number?", 1); let b = prompt("Second number?", 2); alert(+a + +b); // 3
在最新的代碼中,同時(shí)使用一元和二元的
+
。看起來(lái)很有趣,不是嗎?
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: