array 類型的內建函式


Posted by saffran on 2021-02-05

參考資料 Array

join() 用字元連接陣列

join() 會把「陣列的每一個元素」用我想要的「字元」連接在一起之後,產生另一個新的「string」回傳

  • 字元只會插在陣列的空隙,陣列的頭尾不會放入字元
  • join() 最後會回傳一個新的 string
  • 原本的 array 並不會被改變
    var arr = [7, 8, 9]
    console.log(arr.join('!'))
    // output: 7!8!9
    
    如果沒有指定字元的話,預設就會是「每個元素直接連接在一起」
    var arr = [7, 8, 9]
    console.log(arr.join(''))
    // output: 789
    

map()

map()傳入函式

第一種寫法:
map() 小括號裡面傳入一個函式
然後 map() 就會把「原本陣列的每一個元素」當作參數,按照順序傳進這個 double 函式裡面,用「double 函式每一次的回傳值」產生另一個新的陣列

  • map() 最後會回傳另一個新的 array
  • 原本的 array 並不會被改變
var arr = [7, 8, 9]
function double(x){
  return x * 2
}
console.log(arr.map(double))
// output: [ 14, 16, 18 ]

map()傳入匿名函式

這是第二種寫法:
也可以在 map() 的小括號裡面,直接傳入一個匿名函式

var arr = [7, 8, 9]

console.log(arr.map(function (x) {
  return x * 2
}))
// output: [ 14, 16, 18 ]

map() 再接 map()

map() 後面可以接無限多個 map()

  • 第一次 map():對 arr 陣列的每個元素執行 x * 2
  • 第二次 map():用第一次 map() 回傳的新陣列,再針對新陣列的每個元素執行 x * -1
var arr = [7, 8, 9]

console.log(
  arr
  .map(function (x) {
    return x * 2
  })
  .map(function(x){
    return x * -1
  })
)
// output: [ -14, -16, -18 ]

filter() 過濾東西

filter() 可以把東西過濾掉:回傳 true 的東西會留下,回傳 false 的東西會不見

  • filter() 最後會回傳另一個新的 array
  • 原本的 array 並不會被改變

arr 陣列的每個元素當作參數,按照順序傳進 filter() 的函式裡面

  • x > 0 回傳是 true 的元素就會留下
  • x > 0 回傳是 false 的元素就會不見
var arr = [7, -8, 9, 2, -5, 3]

console.log(
  arr
  .map(function(x) {
    return x * 2
  })
  .filter(function(x) {
    return x > 0
  })
)
// output: [ 14, 18, 4, 6 ]

因為 map()filter() 最後都是回傳一個 array,所以 map()filter() 都可以互相接連使用

例如:

var arr = [7, -8, 9, 2, -5, 3]

console.log(
  arr
    .map(function (x) {
      return x * 2
    })
    .filter(function (x) {
      return x > 0
    })
    .map(function(x){
      return x - 1
    })
)
// output: [ 13, 17, 3, 5 ]

注意!因為 join() 最後會回傳的是一個「string」,所以後面就不能再接 map()filter()

原因:string 並沒有 map()filter() 這些函式可以用,所以就會出錯

slice() 擷取陣列的某個部份

  • slice() 會回傳另一個新的 array
  • 原本的 array 並不會被改變

只傳入一個參數

arr.slice(2) 代表:從 arr 陣列的「第 2 個 index 的元素」開始擷取,到最後一個元素我都要

var arr = ['milk', 'biscuit', 'salmon', 'mango', 'noodle']

console.log(arr.slice(2))
// output: [ 'salmon', 'mango', 'noodle' ]

傳入兩個參數

[範例一]

arr.slice(2, 4) 的意思是:

  • 第一個參數:我要從「第 2 個 index 的元素」開始擷取
  • 第二個參數:我要切到第 4 個,但是第 4 個我不要

所以,就只會擷取 index 是 2, 3 的元素

var arr = ['milk', 'biscuit', 'salmon', 'mango', 'noodle']

console.log(arr.slice(2, 4))
// output: [ 'salmon', 'mango' ]

[範例二]

arr.slice(1, 5) 只會擷取 index 是 1, 2, 3, 4 的元素

var arr = ['milk', 'biscuit', 'salmon', 'mango', 'noodle']

console.log(arr.slice(1, 5))
// output: [ 'biscuit', 'salmon', 'mango', 'noodle' ]

splice() 插入、替換元素

splice 是「拼接」的意思
splice() 可以做到兩件事情:

  1. 插入元素
  2. 替換元素
  • splice() 會直接改變原本的 array

例如:
原本的 months 陣列是 ['Jan', 'March', 'April', 'June']

  • 第一次 months.splice(1, 0, 'Feb'):會在 index = 1 的位置用 'Feb' 來「取代 0 個元素」

這時,months 陣列就會變成 ['Jan', 'Feb', 'March', 'April', 'June']

  • 第二次 months.splice(4, 1, 'May'):會在 index = 4 的位置用 'May'「取代 1 個元素」

最後,months 陣列就會變成 ['Jan', 'Feb', 'March', 'April', 'May']

var months = ['Jan', 'March', 'April', 'June']
months.splice(1, 0, 'Feb')
// replaces 0 element at index 1
console.log(months)
// output: [ 'Jan', 'Feb', 'March', 'April', 'June' ]

months.splice(4, 1, 'May')
// replaces 1 element at index 4
console.log(months)
// output: [ 'Jan', 'Feb', 'March', 'April', 'May' ]

sort() 排序

  • sort() 會直接改變原本的 array
  • 是按照「字典序」(字典裡的順序)來排序的

字母

如果是字母的話,就會根據「每個元素的第一個字母」,按照字母的排序(a, b, c...),去重新排序 array 裡的元素

如果第一個字母相同,就比第二個字母

數字

如果是數字的話,不是按照「數字大小」排列,而是會把數字當作「字串」排列,所以是按照「每個元素的第一個數字」的字典序來排序

如果第一個數字相同,就比第二個數字

var animals = ['elephant', 'dog', 'ant', 'cat', 'bird', 'alpaca']
animals.sort()
console.log(animals)
// output: [ 'alpaca', 'ant', 'bird', 'cat', 'dog', 'elephant' ]

var arr = [5, 100000, 1, 25, 9, 213]
arr.sort()
console.log(arr)
// output: [ 1, 100000, 213, 25, 5, 9 ]

讓數字由小到大排列

如果想要讓數字由小到大排列,可以這麼做:
sort() 小括號傳入一個 compareFunction,用這個 function 來告訴 sort() 要怎麼排序

這個 function 會傳入 a, b 這兩個數字當作參數,「由小到大排列」的規則如下:

  1. 如果 a === b,就 return 0
  2. 如果 a < b,也就是「a, b 不用互換位置」,就 return 一個負數
  3. 如果 a > b,也就是「a, b 要互換位置」,就 return 一個正數

最後,把 arr 陣列印出來,就會是我想要的結果了:由小到大排列

var arr = [5, 100000, 1, 25, 9, 213]
// 由小到大排列
arr.sort(function(a, b){
  if(a === b) return 0
  if(a < b) return -1
  return 1
})

console.log(arr)
// output: [ 1, 5, 9, 25, 213, 100000 ]

讓數字由大到小排列

這個 function 會傳入 a, b 這兩個數字當作參數,「由大到小排列」的規則如下:

  1. 如果 a === b,就 return 0
  2. 如果 a > b,也就是「a, b 不用互換位置」,就 return 一個負數
  3. 如果 a < b,也就是「a, b 要互換位置」,就 return 一個正數

最後,把 arr 陣列印出來,就會是我想要的結果了:由大到小排列

var arr = [5, 100000, 1, 25, 9, 213]
// 由大到小排列
arr.sort(function(a, b){
  if(a === b) return 0
  if(a > b) return -1
  return 1
})

console.log(arr)
// output: [ 100000, 213, 25, 9, 5, 1 ]

用三元運算子來寫「由大到小排列」

var arr = [5, 100000, 1, 25, 9, 213]
// 由大到小排列
arr.sort(function(a, b){
  if(a === b) return 0
   return (a > b) ? -1 : 1
})

console.log(arr)
// output: [ 100000, 213, 25, 9, 5, 1 ]

用數學的角度去想

前面講解完原理之後,之後寫題目就直接用a - bb - a 這樣寫即可

「由大到小」排列 return b - a

重點!用一個正確的排序來做假設,會比較容易想。例如 a = 5, b = 1 就是「由大到小」排列

假設 a = 5, b = 1
因為是要「由大到小」排列,所以 a, b 不用換位置--> 就要回傳一個負數,所以要讓 b - a

var arr = [5, 100000, 1, 25, 9, 213]
// 由大到小排列
arr.sort(function(a, b){
  return b - a
})

console.log(arr)
// output: [ 100000, 213, 25, 9, 5, 1 ]

「由小到大」排列 return a - b

重點!用一個正確的排序來做假設,會比較容易想。例如 a = 1, b = 5 就是「由小到大」排列

假設 a = 1, b = 5
因為是要「由小到大」排列,所以 a, b 不用換位置--> 就要回傳一個負數,所以要讓 a - b

var arr = [5, 100000, 1, 25, 9, 213]
// 由小到大排列
arr.sort(function(a, b){
  return a - b
})

console.log(arr)
// output: [ 1, 5, 9, 25, 213, 100000 ]

reduce()

reduce() 的小括號裡面,可以傳入兩個參數

[6, 7, 8, 9].reduce(function (accumulator, currentValue) {
  return currentValue + accumulator
}, 35)

reduce() 第一個參數:是一個 function

  • reduce() 一定要傳入一個 function

reduce() 所傳入的 function 會有兩個參數:

  • 第一個參數 accumulator:就是「累積器」的意思
    --> 這次 return 回來的值,就會是下一次的 accumulator
  • 第二個參數 currentValue:就是「陣列裡面的每一個元素」

reduce() 最後 return 的值,就是「accumulator 最終的值」

reduce() 第二個參數 initialValue: 會是 accumulator 的初始值

  • initialValue 可加可不加

如果沒有設定 initialValue

  • 「陣列的第一個元素」就會是「accumulator 的初始值」
  • 「陣列的第二個元素」就會是「第一個 currentValue

reduce() 是怎麼運作的?

情況一:沒有設定 initialValue

var sum = [6, 7, 8, 9].reduce(function (accumulator, currentValue) {
  return currentValue + accumulator
})

console.log(sum)
// output: 30

陣列 [6, 7, 8, 9] 有 4 個元素,所以 reduce() 小括號裡的 function 總共會執行 3 次

第 1 次:

  • accumulator 的初始值會是 6 (陣列的第一個元素)
  • currentValue 會是 7 (陣列的第二個元素)
  • return 的值會是 6 + 7 = 13

第 2 次:

  • accumulator 會是 13,因為上一次 return 的值 = 13
  • currentValue 會是 8
  • return 的值會是 13 + 8 = 21

第 3 次:

  • accumulator 會是 21,因為上一次 return 的值 = 21
  • currentValue 會是 9
  • return 的值會是 21 + 9 = 30

最後,accumulator 會是 30,所以最後 return 的值就是 30

情況二:有設定 initialValue(會成為 accumulator 的初始值)

var sum = [6, 7, 8, 9].reduce(function (accumulator, currentValue) {
  return currentValue + accumulator
}, 35)

console.log(sum)
// output: 65

陣列 [6, 7, 8, 9] 有 4 個元素,但是因為這次有設定初始值,所以 reduce() 小括號裡的 function 總共會執行 4 次

第 1 次:

  • accumulator 的初始值會是 35 (也就是我設定的 initialValue
  • currentValue 會是 6 (陣列的第一個元素)
  • return 的值會是 35 + 6 = 41

第 2 次:

  • accumulator 會是 41,因為上一次 return 的值 = 41
  • currentValue 會是 7
  • return 的值會是 41 + 7 = 48

第 3 次:

  • accumulator 會是 48,因為上一次 return 的值 = 48
  • currentValue 會是 8
  • return 的值會是 48 + 8 = 56

第 4 次:

  • accumulator 會是 56,因為上一次 return 的值 = 56
  • currentValue 會是 9
  • return 的值會是 56 + 9 = 65

最後,accumulator 會是 65,所以最後 return 的值就是 65

reduce() 的好處是什麼?如果是用 map()forEach() 會有什麼壞處呢?

請參考 這篇


#javascript







Related Posts

JS底層學習筆記 - EventLoop

JS底層學習筆記 - EventLoop

Estimation – ML & MAP 介紹

Estimation – ML & MAP 介紹

React-router-dom 實作與原理解析

React-router-dom 實作與原理解析


Comments