1. 程式人生 > >JavaScript 系列部落格(二)

JavaScript 系列部落格(二)

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,這樣遍歷就不會跳過。

本文參考https://wangdoc.com/javascript/types/array.html