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