JavaScript 系列博客(二) 前言 本篇博客介紹 js 中的運算符、條件語句、迴圈語句以及數組。 運算符 算術運算符 賦值運算符 比較運算符 邏輯運算符 js // 總結&&: 全真為真, 有假則假 // 總結||: 全假則假, 有真則真 // 總結!: 真則假, 假則真 // 邏輯運算符的 ...
JavaScript 系列博客(二)
前言
本篇博客介紹 js 中的運算符、條件語句、迴圈語句以及數組。
運算符
- 算術運算符
// + | - | * | / | % | ++ | --
console.log(5 / 2); // 2.5
// 取整
console.log('%d', 5 / 2); // "2"
var num = parseInt(5 / 2); // 2
console.log(num);
// 取模(求餘)
console.log(5 % 2); // 1
// 任何一個自然數對 n 取餘, 結果為 [0, n-1]
// 自增|自減 ++|--
// ++就是自增1, --就是自減1
var num = 10
console.log(num++); // 10
console.log(++num); // 12
console.log(num); // 12
// ++在變數後(num++), 先將變數的值拿去使用,再自身自增1
// ++再變數前(++num), 先將變數自身自增1, 再將結果拿去使用
// 總結: 不管++在前在後,運算結束後,變數自身值一定自增1
// res = ++num <==> num++; res = num
// res = num++ <==> res = num; ++num
- 賦值運算符
// = | += | -= | *= | /= | %=
var x = 10; // 將10的值賦值給變數x
y = x; // 將變數x的值傳遞給變數y
console.log(y); // 10
x += 10; // x = x + 10, 運算方式由右至左, 將x+10的結果重新複製給x
console.log(y); // 10, y的值雖然來源於x, 但y值只由自身控制
// x /= 10 == x = x / 10
- 比較運算符
// 比較運算符, 結果為Boolean類型
// == | ===
console.log("5" == 5); // true, 只做值比較
console.log("5" === 5); // false, 比較值及類型
// != | !==
console.log("5" != 5); // false, 只做值比較
console.log("5" !== 5); // true, 比較值及類型
- 邏輯運算符
// 總結&&: 全真為真, 有假則假
// 總結||: 全假則假, 有真則真
// 總結!: 真則假, 假則真
// 邏輯運算符的結果本質上為表達式值
// 表達式: 由數字,變數,運算符組成的合法式子
res = a < b && c;
console.log(res);
res = (a = 1 || b == c);
console.log(res);
// 針對 && | ||
// 疑問: 邏輯運算符結果可能為邏輯運算符之前表達式的值,也可能是之後表達式的值
針對邏輯運算符,會出現短路現象。當運算符為&&時,如果第一個表達式的結果為假,那麼第二個表達式就不會執行;同理,||當第一個表達式的結果為真時,第二個表達式就不會執行(python 在邏輯判斷也會出現短路現象)
- 三目運算符(等同於 python 中的三元表達式)
// 語法: 條件表達式 ? 表達式1 : 表達式2
var a = 10, b = 20;
var res = a < b ? a : b; // 取小值
console.log(res);
res = a < b ? b : a; // 取大值
console.log(res);
// 類似於if...esle...
a < b ? console.log("表達式結果為true") : console.log("表達式結果為false")
三目表達式可以看做 if...else 的簡寫形式。
程式結構
根據執行方式程式可以分為三大結構:順序結構、分支結構、迴圈結構。其實只有一種結構就是順序結構,像分支結構本質還是順序執行的,只不過選擇多了;而迴圈結構也是一樣的道理。
條件語句
if 結構
if結構首先判斷後面表達式的布爾值,然後決定是否執行後面的代碼。布爾值只有兩個,true 為真,false 為假。
// 語法
if (表達式1) {
語句; };
// 或
if (表達式2) {語句};
上面是 if 結構的基本形式。需要註意的是,‘’布爾值‘’往往是由一個條件表達式產生的,必須放在圓括弧中,表達對該表達式求值。如果表達式的結果為 true,就執行後面的代碼語句;如果為 false,則跳過後面的語句。
if...else 結構
跟 python 一樣,if 後面也可以跟 else 代碼塊,表示不滿足條件時,要執行的代碼塊。
if (表達式3) {
//表達式結構為真時,執行的代碼
} else {
// 表達是結構為假時,執行的代碼
}
如果需要對於一個表達式進行多次判斷時,多個 if...else 語句可以連到一起。
if (表達式4) {
} else if {表達式5} {
} else if {表達式6} {
} else {
} // 註意:else 代碼塊總是與離自己最近的那個 if 語句配對
switch 分支
// 語法
switch (結果為整數|字元串的表達式) {
case 值1(值需要和表達式進行類型統一): 代碼塊; break;
...
case 值n: 代碼塊; break;
default: 代碼塊;
}
// 需要註意的是,switch 語句後面的表達是,與 case 語句後面的表達是比較運行結果時,採用的是嚴格相等運算符(===),而不是相等運算符(==),這意味著比較時不會發生類型轉換。
// break作用是結束分支結構(結束所屬switch語句),可以省略。
default 分支
default分支,出現在所有case之下,當所有case沒有匹配上,走該分支,該分支也可以省略,代表沒有未匹配到的動作。
迴圈語句
迴圈語句用於重覆執行某個操作,直到條件不滿足跳出迴圈。
while 迴圈
while 迴圈包括一個迴圈條件和一段代碼塊,只要條件為真,就會不斷執行代碼塊。
while (條件表達式) {
語句;
}
while語句的迴圈條件為一個條件表達式,必須放在圓括弧中,表示需要先計算表達式的結果才能進行是否進行迴圈。代碼塊部分,如果只有一條語句,可以省略大括弧。
var i = 0;
while (i < 100) {
console.log('i 為:' + i);
i++;
}
這段代碼會迴圈100次,直到i 等於100。
for 迴圈
for 迴圈是迴圈結構的另一種形式,可以指定迴圈的起點、終點和終止條件。格式如下:
/*
for (迴圈變數定義並初始化①; 迴圈變數條件表達式②; 迴圈變數增量③) {
代碼塊④;
}
執行順序 ① ②④③ ... ②④③ ②, ②④③個數就是迴圈次數
*/
for (var i = 0; i < 5; i++) {
console.log("我最棒, 我最帥, 我是天下第一!");
}
上段代碼圓括弧裡面有三個表達式:
- 表達式①(initialize):確定迴圈變數的初始值,只在迴圈開始時執行一次。
- 表達式②(test):每輪迴圈開始時,都需要執行判斷,只有判斷為真時,才會繼續迴圈。
- 表達式③(increment):每輪迴圈的最後一個操作,通常用來遞增迴圈變數。
所有 for 迴圈,都可以用 while 迴圈實現。
for 迴圈裡面的三個表達式可以省略其中任何一個,也可以全部省略。
for ( ; ; ) {
console.log('Hello MUSIBII!');
}
這段代碼省略了 for 表達式的三個部分,結果就導致了一個無限迴圈。
do...while 迴圈
do...while 迴圈和 for 迴圈類似,唯一區別就是 do 迴圈不管條件滿不滿足都會執行一次迴圈,之後進行第二次迴圈才會進行判斷條件。
do
代碼塊
while (條件表達式);
// 或
do {
代碼
} while (條件表達式);
不管條件是否為真,do...while 迴圈至少需要運行一次,這是和while 迴圈的本質區別。另外 while 語句後面的分號不要省略。
var x = 3;
var y = 0;
do {
console.log(y);
y++;
} while(y < x);
break 和 continue 語句
只要有迴圈就少不了 break 和 continue,這兩個關鍵詞都具有跳轉作用,可以控制代碼的執行順序。
- break 語句用於跳出迴圈體
var i = 0;
while(i < 100) {
console.log('i 為:' +i);
i++;
if (i === 10) break;
}
當 i 等於10時,if 表達式判斷為真,執行 break 跳出迴圈體
- continue 語句用於立即終止本輪迴圈,進入下次迴圈。
var i = 0;
while(i < 100) {
if (i % 2 === 0) continue;
console.log('i 為:' +i);
i++;
}
這段代碼只有 i 為奇數時,才會輸出 i 的值。如果 i 為偶數,則直接進入下一輪迴圈。如果存在多重迴圈,不帶參數的 break 語句和 continue 語句都只針對本層迴圈。
數組
數組的定義
數組(Array)是按照次序排列的一組值。每個值得索引從0開始,數組使用中括弧表示。
var array = ['a', 'b', 'c', 1, 2, 3];
這樣,array 就構成一個數組,兩端的方括弧是數組的標誌。'a' 是0號位置,3是5號位置。
除了在定義時賦值,數組也可以先定義後賦值。(通過構造函數(constructor))
var array = [];
array[0] = 'hello';
array[1] = 'world';
任何類型的數據,都可以放入數組(類比 python 的列表)。
特別的,如果數組的元素還是數組,則形成了多維數組。
數組的本質
本質上,數組是對象類型的一種,typeof 運算符會返回數組的類型為 object。
typeof(['a', 'b', 'c']) // object
這表明,數組類型為對象。數組的特殊性體現在,它的鍵名是按次序排列的一組整數(從0開始)。
var array = ['a', 'b', 'c'];
Object.keys(array) // ['0', '1', '2']
通過 Object 的 keys 方法可以返回指定數組的所有鍵名。
由於數組成員的鍵名是固定的,因此數組不用為每個元素指定鍵名,而對象的每個成員都必須指定鍵名。JavaScript 語言規定,對象的鍵名一律為字元串,所以,數組的鍵名其實也是字元串。之所以可以用數值取值,是因為非字元串的鍵名會被轉為字元串。
var array = ['a', 'b', 'c'];
array[0]; // 'a'
array['0']; // 'a'
這點在賦值時也會成立(js 的數據類型轉換需要註意),一個值總是先轉成字元串,再進行賦值。
var a = [];
a[1.00] = 'c';
a[1]; // 'c'
賦值時,先把1.00轉為字元串1,賦值結束後可以通過數字鍵1取值。
length 屬性
數組的 length 屬性返回數組的成員數量。
array.length // 3
JavaScript 使用一個32位整數,保存數組的元素個數。這意味著,數組成員最多只用(2^32 - 1)個,也就是說 length 屬性的最大值就是4294967295。
只要是數組就一定有 length 屬性。該屬性是一個動態的值(因為可以動態賦值)。數組的數字鍵不需要連續,length 屬性的值總是比最大的那個整數鍵大1.另外,數組是一種動態的數據結構,可以隨時增減數組成員。
註意:length 屬性是可寫的。如果認為的設置一個小於當前成員個數的值,該數組的成員會自動減少到 length 設置的值。
var array = ['a', 'b', 'c'];
array.length; // 3
array.length = 2;
array // ['a', 'b']
這表明當數組的 length 屬性值設為2,那麼整數鍵2就會被刪除。這樣清空一個數組就可以直接把 length 屬性值設為0就 ok 了。
如果人為設置 length 值大於當前數組元素個數,那麼數組的成員數量會增加到這個值,新增的位置都是空(undefined)。
var array = ['a'];
a.length = 2;
a[1]; // undedined
當 length 屬性值設為大於數組個數時,讀取新增的位置都會返回 undefined。如果設置的不合法,比如設置一個非整數的值時,JavaScript 會報錯。
var array = [];
array.length = -1;
// RangeError: Invalid array length
array.length = Math.pow(2, 32);
// RangeError: Invalid array length
array.length = 'abc';
// RangeError: Invalid array length
因為數組的本質是一種對象,所以可以為數組添加屬性,但是這不會影響數組的 length 屬性。
var array = ['a'];
array['name'] = 'musibii';
array.length; // 1
註意:如果數組添加的鍵名超過範圍的數值,該鍵名會自動轉化為字元串。
var array = [];
array[-1] = 'a';
array[Math.pow(2, 32)] = 'b';
array.length //0
array[-1]; // 'a'
array[4294967296]; // 'b'
上面為數組添加了兩個不合法的數字鍵,並不會影響到 length 的值。這些數字鍵都變成了字元串鍵名。最後兩行會取到值是因為會把數字轉為字元串。
in 運算符
檢查某個鍵名是否存在於數組中,使用 in 運算符,這個適用於對象,自然也適用於數組。
var array = ['a', 'b', 'c', 1, 2, 3];
2 in array; // true
'2' in array; // true
6 in array; // false
數組存在鍵名為2的鍵,由於鍵名都為字元串,所以數值2會自動轉成字元串。
var array = [];
array[100] = 'a';
array.length; // 101
array[1]; // undefined
1 in array; // false
數組 array 只有一個成員,雖然 length 為101,但是其他位置的鍵名都會返回 false。
for...in 迴圈和數組的遍歷
for...in 迴圈不僅可以遍歷對象,也可以遍曆數組。因為數組是對象。
var array = ['a', 'b', 'c'];
for (var i in array) {
console.log(array[i]);
}
// 'a', 'b', 'c' 換行列印
for...in 不僅會遍曆數組所有的數字鍵,也會遍歷非數字鍵。
var array = ['a', 'b', 'c'];
array.name = 'musibii';
for (var i in array) {
console.log(array[i]);
}
// 'a', 'b', 'c', 'musibii'
在遍曆數組時,也會遍歷非整數鍵name,所以不建議使用for...in 遍曆數組。可以使用 for 迴圈或者 while 迴圈。(這樣只會遍歷出整數的鍵名)
數組的空位
當數組的某個位置是空元素,即兩個逗號之間沒有任何值,那麼稱該數組存在空位。
var array = ['a', '', 'c'];
array.length; // 3
array[1]; // undefined
這表名數組的空位不影響 length 屬性的值。 並且空位是可以被讀取的,只不過值為 undefined。
使用 delete 命令可以刪除數組中的某個成員,這樣會形成空位,和上面一樣不會影響數組的 length 屬性。
var array = ['a', 'b', 'c'];
delete array[1];
a[1]; //undefined
a.length; // 3
使用 delete 刪除了數組中的元素,不會影響數組的 length 屬性值,這樣如果使用 length 對一個數組進行遍歷時需要謹慎(這好奇怪啊。。。。)
數組的某個位置是空位,與某個位置是 undefined,是不一樣的。如果是空位,使用數組的 forEach 方法、for...in 結構以及 Object.keys 方法進行遍歷時,空位會被跳過。
不得不說,真的奇怪。這個設計思想也太靈活了8。。。
空位表示數組沒有這個元素,所以不會被遍歷到,而 undefined 表示數組有這個元素,值為 undefined,這樣遍歷就不會跳過。