Array 類型

ECMAScript 數組的每一項可以保存任何類型的數據。

ECMAScript 數組的大小是可以動態調整的,既可以隨著數據的添加自動增長以容納新數據。

創建數組的方法

  1. 使用 Array 構造函數

    使用 new Array(), new 可以省略不寫。

    1
    2
    3
    4
    var colors = new Array();
    var colors = Array();
    var colors = new Array(20); // 創建長度為20的數組
    var colors = new Array("red","blue","green") // 創建包含3個字符串的數組

    javascript-array-new-array

    Untitled

  2. 使用數組字面量表示法

    1
    2
    3
    4
    var color = ['red','blue']
    var color = [] // 空數組
    var color = [1,2,] // ie8及之前的版本,會是一個包含1,2,undefined 的數組(長度3),其它的瀏覽器會生成一個包含1,2的數組(長度2)
    var color = [,,,,,] // ie8及之前會創建包含6項的數組,其它的瀏覽器可能會創建包含5項的數組。每一項都是 undefined

讀取和設置數組的值

1
2
3
4
var color = ['red','blue','green']
color[0] // red 獲取第一項
color[1] = 'black' // 修改第二項
color[3] = 'yellow' // 新增第四項

數組長度

可以通過 length 獲取長度。也可以用 length 來從數組的末尾移除項或向數字添加項。

1
2
3
4
5
6
7
8
9
10
11
12
13
var colors = ['red','yello','blue']
var tt = []

console.log(colors.length) // 3
console.log(tt.length) // 0

colors.length = 2 // 數組長度變為2, blue 被移除
console.log(colors[2]) // undefined

// 向 99 插入一個值後,長度變為 100, 而位置 3 到位置 98 實際上都是不存在的,所以訪問它們都會返回 undefined
var num = [1,2,3]
num[99] = 99
console.log(num.length) // 100

檢測數組 - Array.isArray()

可以通過 Array.isArray() 來判斷是不是數組

1
2
const arr = [1,2,3,4]
console.log(Array.isArray(arr)) // true

轉換方法 - toLocaleString() / toString() / valueOf() / join()

所有的對象都具有 toLocaleString()toString()valueOf() 方法。

在這四個方法中,如果一個元素為 undefined 或 null,它會被轉換為空字符串。

  • valueOf()

    返回對象的原始值,即數組本身

    1
    2
    3
    var a = [1,2,3,4]
    console.log(a.valueOf()) // [1,2,3,4]
    console.log(a.valueOf() === a) // true

    Untitled 1-1615395626374

  • toString()

    返回一個字符串,表示指定的數組和元素,用逗號相連。

    1
    2
    var ab = [1,2,'3a','ab']
    console.log(ab.toString()) // 1,2,3a,ab
  • toLocaleString()

    返回一個字符串表示數組中的元素。數組中的元素將使用各自的 toLocaleString() 方法轉成字符串,這些字符串將使用一個特定語言環境的字符串(例如一個逗號 “,”)隔開

    1
    2
    3
    4
    5
    6
    const array1 = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
    const localeString = array1.toLocaleString('en', { timeZone: 'UTC' });

    console.log(localeString);
    // expected output: "1,a,12/21/1997, 2:12:00 PM",
    // This assumes "en" locale and UTC timezone - your results may vary
  • join()

    將一個數組的所有元素連接成一個字符串並返回這個字符串。默認為 逗號(,)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var val = [1,2,3,4]
    console.log(val.join()) // 1,2,3,4
    console.log(val.join("")) // 1234
    console.log(val.join("||")) // 1||2||3||4

    var val2 = [1,2,null,3,undefined,4]
    console.log(val2.join()) // 1,2,,3,,4
    console.log(val2.join("")) // 1234
    console.log(val2.join("||")) // 1||2||||3||||4

push() 和 pop()

  • push()

    接受一個或多個參數,並將其添加到數組末尾,並返回修改後的數組長度。

    1
    2
    3
    4
    var colors = ['red','yellow','blue']
    var count = colors.push('red','black')
    console.log(colors) // ["red", "yellow", "blue", "red", "black"]
    console.log(count) // 5
  • pop()

    刪除數組中的最後一個元素,並返回被刪除的元素值

    1
    2
    3
    4
    var colors = ["red", "yellow", "blue", "red", "black"]
    var val = colors.pop()
    console.log(colors) // ["red", "yellow", "blue", "red"]
    console.log(val) // black

shift() 和 unshift()

  • shift()

    刪除數組中的第一個元素,並返回該元素。

    1
    2
    3
    4
    var colors = ["red", "yellow", "blue", "red", "black"]
    var val = colors.shift()
    console.log(colors) // ["yellow", "blue", "red", "black"]
    console.log(val) // red
  • unshift()

    接受一個或多個參數,並將其添加到數組開頭,並返回修改後的數組長度。

    1
    2
    3
    4
    var colors = ["blue", "red", "black"]
    var count= colors.unshift('red','yellow')
    console.log(colors) // ["red", "yellow", "blue", "red", "black"]
    console.log(count) // 5

重排序方法 - reverse() 和 sort()

  • reverse()

    會反轉數組的順序,並返回新的數組。

    1
    2
    var val = [1,2,3,4,5]
    console.log(val.reverse()) // [5,4,3,2,1]
  • sort()

    會用 原地算法 對數組的元素進行排序,並返回數組。默認的排序會將元素轉為字符串,然後比較它們的 UTF-16代碼單元值序列時構建的

    由於它一定具體實現,因此無法保證排序的時間和空間複雜性。

    sort 會調用每個數組項的 toString() 轉型方法,然後比較得到的字符串。每個字符串由左到右進行對比。

    1
    2
    3
    4
    5
    6
    7
    8
    9

    var val = [1,2,8,4,5]
    console.log(val.sort()) // [1,2,4,5,8]

    var val2 = ['March', 'Jan', 'Feb', 'Dec']
    console.log(val2.sort()) // ["Dec", "Feb", "Jan", "March"]

    var val3 = [1,2,3,10,8]
    console.log(val3.sort()) // [1, 10, 2, 3, 8]

    sort([compareFunction]) 可以接收一個比較函數作為參數,用來指定按某種順序進行排列的函數。如果省略,元素按照轉換為的字符串的各個字符的Unicode位點進行排序

    如果沒有指明 compareFunction ,那麼元素會按照轉換為的字符串的諸個字符的Unicode位點進行排序。例如 “Banana” 會被排列到 “cherry” 之前。當數字按由小到大排序時,9 出現在80 之前,但因為(沒有指明compareFunction),比較的數字會先被轉換為字符串,所以在Unicode順序上”80” 要比”9” 要靠前。

    如果指明瞭 compareFunction ,那麼數組會按照調用該函數的返回值排序。即 a 和 b 是兩個將要被比較的元素:

    1. 如果 compareFunction(a, b) 小於 0 ,那麼 a 會被排列到 b 之前;
    2. 如果 compareFunction(a, b) 等於 0 , a 和 b 的相對位置不變。備註: ECMAScript 標準並不保證這一行為,而且也不是所有瀏覽器都會遵守(例如 Mozilla 在 2003 年之前的版本);
    3. 如果 compareFunction(a, b) 大於 0 , b 會被排列到 a 之前。
      compareFunction(a, b) 必須總是對相同的輸入返回相同的比較結果,否則排序的結果將是不確定的。

    以數字比較為例

    1
    2
    3
    var val4 = [1,21,3,10,8]
    var compareFn = (a,b) => a-b
    console.log(val4.sort(compareFn)) // [1, 3, 8, 10, 21]

操作方法 - concat() 、 slice() 和 splice()

  • concat()

    基於當前數組中的所有項創建一個新數組。concat() 並不會修改原數組

    這個方法會創建當前數組的一個副本,並把接收到的參數添加到副本的末尾。

    concat方法創建一個新的數組,它由被調用的對像中的元素組成,每個參數的順序依次是該參數的元素(如果參數是數組)或參數本身(如果參數不是數組)。它不會遞歸到嵌套數組參數中。

    concat方法不會改變this或任何作為參數提供的數組,而是返回一個淺拷貝,它包含與原始數組相結合的相同元素的副本。原始數組的元素將復製到新數組中,如下所示:

    • 對象引用(而不是實際對象):concat將對象引用複製到新數組中。原始數組和新數組都引用相同的對象。也就是説,如果引用的對像被修改,則更改對於新數組和原始數組都是可見的。這包括也是數組的數組參數的元素。

    • 數據類型如字符串數字和布爾(不是String,Number 和 Boolean 對象):concat將字符串和數字的值複製到新數組中。

    1
    2
    3
    4
    5
    6
    7
    var val = [1,2,3,4]
    var val2 = [5,6,7,8]
    console.log(val.concat(val2)) // [1,2,3,4,5,6,7,8]
    console.log(val) // [1,2,3,4] 原數組並不會改變

    var val3 = [9,10,11,12]
    console.log(val.concat(val2,val3)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 可以接受多於一個參數
  • slice()

    它能夠基於當前數組中的一個或多個項創建一個新數組。

    slide(begin,end) 可以接受一個或兩個參數。這方法不會影響原始數組

    • 一個參數

      當只有一個參數時,會返回該參數從該參數指定位置開始到當前數組末尾的所有項

      如果省略 begin,則 slice 從索引 0 開始。

      如果 begin 超出原數組的索引範圍,則會返回空數組。

    • 兩個參數

      有兩個參數時,會返回起始和結束位置之間的項,但不包括結束位置的項。

      如果 end 被省略,則 slice 會一直提取到原數組末尾。
      如果 end 大於數組的長度,slice 也會一直提取到原數組末尾。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      var val = ['a','b','c','d','e']

      // 如果省略 begin,則 slice 從索引 0 開始
      console.log(val.slice()) // ['a','b','c','d','e']
      // 如果 end 被省略,則 slice 會一直提取到原數組末尾。
      console.log(val.slice(1)) // ["b", "c", "d", "e"]

      console.log(val.slice(1,4)) // ["b", "c", "d"] 不包括結束的位置 'e'
      console.log(val.slice(-4,-1)) ["b", "c", "d"]

      // 如果 begin 超出原數組的索引範圍,則會返回空數組
      console.log(val.slice(4,1)) // []
      console.log(val.slice(7)) // []
      // 如果 end 大於數組的長度,slice 也會一直提取到原數組末尾
      console.log(val.slice(1,7)) // ["b", "c", "d", "e"]

      參數可能是負數,我們可以用數組長度加上該數來確認位置。 slice(-4,-1) 等同於 slice(1,4)

    • splice()

      splice() 方法可以藉由刪除既有元素並/或加入新元素來改變一個陣列的內容。

      其會返回被刪除的元素陣列,如沒有刪除,則返回空數組。

      array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

      • start:

        陣列中要開始改動的元素索引(起始為 0)。若索引大於陣列長度,則實際開始的索引值會被設為陣列長度。若索引為負,則會從陣列中最後一個元素開始往前改動(起始為 -1)且若其絕對值大於陣列的長度,則會被設為 0。

      • deleteCount: 一個表示欲刪除的原陣列元素數量的整數。

        若省略了 deleteCount,或假如其值大於 array.length - start(也就是 deleteCount 大於 start 算起的剩餘元素數量),則所有從 start 開始到陣列中最後一個元素都會被刪除。

        若 deleteCount 為 0 或是負數,則不會有元素被刪除。 因此,你應該給定至少一個欲加入的新元素

      • item1, item2, …

        從 start 開始,要加入到陣列的元素。 如果你沒有指定任何元素,則 splice() 只會依照 start 和 deleteCount 刪除陣列的元素。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        // 刪除
        var val = ['a','b','c','d','e','f']
        console.log(val.splice(3)); // ["d", "e", "f"] **被刪除的元素陣列,沒指定刪除個數,之後的參數全部刪除**
        console.log(val); // ["a", "b", "c"]

        var val2 = ['a','b','c','d','e','f']
        console.log(val2.splice(6)) // [] 超過陣列長度,則實際開始的索引值會被設為陣列長度。
        console.log(val2); // ["a", "b", "c", "d", "e", "f"]

        var val3 = ['a','b','c','d','e','f']
        console.log(val3.splice(2,2)); // ["c", "d"] 刪除2個,位置2和3被刪除
        console.log(val3); // ["a", "b", "e", "f"]
        1
        2
        3
        4
        // 插入
        var val = ['a','b','c','d','e']
        console.log(val.splice(3,0,'ee','rr')) // [] 沒有刪除,返回空數組
        console.log(val) // ["a", "b", "c", "ee", "rr", "d", "e"] 由位置3 插入'ee','rr'
        1
        2
        3
        4
        // 替換
        var val = ['a','b','c','d','e']
        console.log(val.splice(3,1,'ee','rr')) // ["d"] 位置3被刪除
        console.log(val) // ["a", "b", "c", "ee", "rr", "e"] 位置3被替換成 'ee','rr'

    位置方法 - indexOf() 和 lastIndexOf()

    indexOf()lastIndexOf() 都接受兩個參數: 要查找的項 和 (可選)表示查找起點位置的索引

    返回值: 在陣列中找到的第一個元素索引值;沒找到則為 -1

    indexOf() 是從數組的開頭向後查找。

    lastIndexOf()則從數組的末尾開始向前查找。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // indexOf()
    var val = ['a','b','c','d','e','c','g']
    console.log(val.indexOf('c')) // 2
    console.log(val.indexOf('c',3)) // 5

    // 從位置-1開始找,-1即是位置6,然後向後查找,沒有找到返回 -1
    console.log(val.indexOf('c', -1)) // -1
    // 從位置-4開始找,-4即是位置3,然後先後查找,直到位置5找到,返回 5
    console.log(val.indexOf('c',-4)) // 5
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // lastIndexOf()
    var val = ['a','b','c','d','e','c','g']
    console.log(val.lastIndexOf('c')) // 5

    // 從位置3 開始向前查找
    console.log(val.lastIndexOf('c',3)) // 2

    // 從位置-6開始向前找,-6即位置1,沒有找到返回 -1
    console.log(val.lastIndexOf('c', -6)) // -1
    // 從位置-4開始找,-4即是位置3,然後先前查找,直到位置2找到,返回 2
    console.log(val.lastIndexOf('c',-4)) // 2

迭代方法 - every() / filter() / forEach() / map() / some()

這5個方法都接受2個參數

  1. 要在每一項運行的函數

    函數會接受三個參數

    1. 目前正要被處理的元素
    2. 【可選】目前正要被處理的元素之索引值
    3. 【可選】數組對象本身
  2. 【可選】運行該函數的作用域對象 - 影響 this 的值

  • every()

    對數組中的每一項運行給定的函數,如果該函數對每一項都返回 true, 則返回 true。(全部都要返回 true

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    var val = [1,2,3,4,5]

    // 判斷數組的每一項都小於 10
    var result = val.every(val => val < 10)
    console.log(result) // true

    // 判斷數組的每一項都小於 4
    var result2 = val.every(val => val < 4)
    console.log(result2) // false 4和5不符合小於4
  • some()

    對數組中的每一項運行給定的函數,至少有一項是返回 true, 則返回 true。(只要一個返回 true

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var val = [1,2,3,4,5]

    // 判斷只要有一項小於 10
    var result = val.some(val => val<10)
    console.log(result) // true

    // 判斷只要有一項小於 4
    var result2 = val.some(val => val < 4)
    console.log(result2) // true
  • filter()

    利用指定的函數來返回數組中符合函數的數組元素。不會修改原數組。

    1
    2
    3
    // 返回大於 3 的元素
    var val = [1,2,3,4,5]
    console.log(val.filter(i => i > 3)) // [4,5]
  • map()

    返回一個數組,而這個數組的每一項都是在原始數組中對應項上運行傳入函數的結果。不會修改原數組。

    1
    2
    3
    // 返回一個數組 ,其每一項都是原數組對應項的值乘以 3
    var val = [1,2,3,4,5]
    console.log(val.map(i => i * 3)) // [3,6,9,12,15]
  • forEach()

    它只是對數組中的每一項運行傳入的函數。這個數組沒有返回值。跟 for 循環本質一樣。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    // 輸出數組中的每一項
    var val = [1,2,3,4]
    val.forEach(i => {
    console.log(i)
    })

    // 1
    // 2
    // 3
    // 4

歸並方法 - reduce() 和 reduceRight()

兩個方法都是接受兩個參數

  1. 用於處理每一個元素的函數 callback

    該函數接受4個參數

    1. accumulator 前一個值(上一次函數返回的纍加值)或 初始值(如有提供)
    2. currentValue 當前值
    3. 【可選】currentIndex 項的索引,若有傳入 initialValue,則由索引 0 之元素開始,若無則自索引 1 之元素開始。
    4. 【可選】 array 數組對象
  2. 【可選】initialValue 作為歸並基礎的初始值,如果沒有初始值,這數組的第一個元素將會作為初始值。

  • reduce()

    將一個累加器及數組中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。

    1
    2
    3
    4
    5
    6
    // 把數組的所有項從左到右相加
    var val = [1,2,3,4,5]
    console.log(val.reduce((acc, cur) => acc + cur)) // 1 + 2 + 3 + 4 + 5 = 15

    // 以 100 為 初始值,並把數組的所有項從左到右相加
    console.log(val.reduce((acc, cur) => acc + cur, 100)) // 100 + 1 + 2 + 3 + 4 + 5 = 115
  • reduceRight()

    將一個累加器及數組中每項元素(由右至左)傳入回呼函式,將陣列化為單一值。

    1
    2
    3
    4
    5
    6
    // // 把數組的所有項從右到左相加
    var val = [1,2,3,4,5]
    console.log(val.reduce((acc, cur) => acc + cur)) // 5 + 4 + 3 + 2 + 1 = 15

    // 以 100 為 初始值,並把數組的所有項從左到右相加
    console.log(val.reduce((acc, cur) => acc + cur, 100)) // 100 + 5 + 4 + 3 + 2 + 1 = 115

copyWithin()

copyWithin() 方法會對數組的一部分進行淺拷貝至同一數組的另一位置並回傳此陣列,而不修改其大小。

返回被修改後的數組,原數組也會被修改。

arr.copyWithin(target, start, end)

  • target

    要複製序列到這個位置的索引

    如果是負數,target 從末尾開始算

    如果 targrt 大於等於 arr.length, 則沒有項目被複製

  • 【可選】start

    開始複製的起始元素索引(起始為 0 )

  • 【可選】end

    結束複製的元素索引,會從 start 複製到 end, 但是不包括 end 的值

    如果省略 end,將會一路複製到數組末項

1
2
3
4
5
6
7
8
9
10
11
var val = [1,2,3,4,5,6]
console.log(val.copyWithin(3)) // [1,2,3,1,2,3]

var val2 = [1,2,3,4,5,6]
console.log(val2.copyWithin(3,2)) // [1,2,3,3,4,5]

var val3 = [1,2,3,4,5,6]
console.log(val3.copyWithin(3,2,5)) // [1,2,3,3,4,5]

var val4 = [1,2,3,4,5,6]
console.log(val4.copyWithin(8,2,5)) // [1,2,3,4,5,6] // target 超過數組長度

fill()

會將數組中索引的第一個到最後一個的每個位置全部填入一個靜態的值。

arr.fill(value[, start[, end]])

  • value

    想要插入的值

  • 【可選】start

    起始的位置,預設為 0

  • 【可選】end

    結束的位置,預設為 數組長度

    注意:不包括 end 的位置

1
2
3
4
5
6
7
8
9
10
11
// 沒有 start 和 end,所以從 0 到數組的長度
var val = [1,2,3,4,5]
console.log(val.fill(5)) // [5,5,5,5,5]

// 只有 start 沒有 end,從 start 到數組結尾
var val2 = [1,2,3,4,5]
console.log(val2.fill(5,3)) // [1,2,3,5,5]

// 有 start 也有 end, 從star 到 end (不包括 end) 插入 5
var val3 = [1,2,3,4,5]
console.log(val3.fill(5,2,3)) // [1,2,5,4,5]

find() 和 findIndex()

  • find()

    返回第一個滿足函數條件的元素值,否則返回 undefined

    arr.find(callback[, thisArg])

    接受 2 個參數 callback 和 thisArg

    • callback 函數

      會處理數組每一個元素的函數,它接受三個參數

      • element

        正被處理的函數

      • 【可選】index

        正被處理的函數索引

      • 【可選】array

        呼叫 find 方法的數組

    • 【可選】thisArg

      執行 callback 函式時被當作 this 的物件

      1
      2
      3
      4
      // 返回符合 大於3 的第一個元素
      var val = [1,2,3,4,5]
      var fn = i => i > 3
      console.log(val.find(fn)) // 4
    • findIndex()

      返回第一個滿足函數條件的元素值索引,否則返回 -1

      其與 find()的區別在於,前者返回的元素值,後者返回的是元素值的索引值

      arr.findIndex(callback[, thisArg])

      接受 2 個參數 callback 和 thisArg

      • callback 函數

        會處理數組每一個元素的函數,它接受三個參數

        • element

          正被處理的函數

        • 【可選】index

          正被處理的函數索引

        • 【可選】array

          呼叫 find 方法的數組

      • 【可選】thisArg

        執行 callback 函式時被當作 this 的物件

        1
        2
        3
        4
        // 返回符合 大於3 的第一個元素索引
        var val = [1,2,3,4,5]
        var fn = i => i > 3
        console.log(val.findIndex(fn)) // 3

參考

  1. 書籍 《JavaScript 高級程序設計》
  2. MDN 文檔