陣列方法不混淆

pubdreamcc發表於2019-07-18

多且易亂的陣列方法

js 中對陣列操作比比皆是,不管是單純前端運算元組變數,還是後臺返回的陣列形式介面資料,都需要用到陣列一些方法運算元組。不知道大家是不是和我一樣經常忘記或混亂陣列一些方法,什麼 find()some()reduce()等等,還有哪些會改變原始陣列哪些返回新陣列,真是一頭霧水。

來張圖片壓壓驚

陣列方法不混淆

這張圖是我收藏的陣列方法圖,上面列出了常見的陣列方法及解釋,介面很舒服,應該一看就懂。

看我整理

建構函式 Array 專屬

Array建構函式的方法常見有三種:

Array.isArray(obj)--- 判斷物件是否為陣列,返回布林

Array.isArray([]) // true
Array.isArray({}) // false
建立新陣列

下面兩種方法意在建立新陣列,所以我總結在一個大類裡面。

比較常見的有兩種建立形式,大家可以理解分類記憶。

  1. 可以指定規則:從一個迭代器物件或一個偽陣列按照一定規則生成新的陣列。

Array.from(arrayLike[, mapFn[, thisArg]])

引數:

arrayLike
想要轉換成陣列的偽陣列物件或可迭代物件。

mapFn (可選引數)
既然有規則,必定需要指定規則函式。

thisArg(可選引數)
可選引數,執行回撥函式 mapFn 時 this 物件。

Array.from('foo')
// ["f", "o", "o"]

let m = new Map([[1, 2], [2, 4], [4, 8]])
Array.from(m)
// [[1, 2], [2, 4], [4, 8]]

Array.from([1, 2, 3], x => x + x)
// [2, 4, 6]
  1. 沒有規則,直接生成

Array.of(element0[, element1[, ...[, elementN]]])

引數:

任意引數

Array.of(1)        // [1]
Array.of(1, 2, 3)  // [1, 2, 3]
Array.of(undefined) // [undefined]

例項物件專屬

例項物件的方法是最多的,也是大家容易混淆的,推薦大家從三個大類去記憶。

可以改變原陣列(9個)

splice() 刪除元素並且向陣列新增新元素

array.splice(index,howmany,item1,.....,itemX)

引數:

index:必需。整數,規定新增/刪除專案的位置,使用負數可從陣列結尾處規定位置。

howmany:必需。要刪除的專案數量。如果設定為 0,則不會刪除專案。

item1, ..., itemX: 可選。向陣列新增的新專案。


var fruits = ["Banana", "Orange", "Apple", "Mango"]

fruits.splice(2,1,"Lemon","Kiwi")

// 結果
// [Banana,Orange,Lemon,Kiwi,Mango]

splice() 方法在 ES5 中常用來陣列去重,相當經典。

var arr = [1,2,2,3,4,2]
  for(var i=0; i<arr.length; i++){
    for(var j=i+1; j<arr.length; j++){
      if(arr[i]==arr[j]){         //如果第一個和第二個一樣,splice方法減去第二個;
        arr.splice(j,1)
        // 設定j-- 防止刪除元素後,下面第一位元素遺漏
        j--
      }
    }
  }
// arr [1, 2, 3, 4]
sort() 排序陣列

引數:排序規則函式或無引數

沒有引數:則按照元素的字母升序,如果不是元素不是字串的話,會呼叫toString()方法將元素轉化為字串的Unicode(萬國碼)位點,然後再比較字元。

排序規則函式:排序規則函式接受兩個引數:a , b,返回一個正數或負數。這裡教大家一個簡單記憶方法:升序不變返回負,降序改變返回正


var a = [1,3,3,5,2,0]  
a.sort()
// [0, 1, 2, 3, 3, 5]

a.sort((a, b) => {
  return a-b // 升序不變返回負,不變指引數位置不變
})
// [0, 1, 2, 3, 3, 5]

a.sort((a, b) => {
  return b-a // 降序改變返回正
})
// [5, 3, 3, 2, 1, 0]

下面就是兩組頭尾刪除和新增方法,可以對應記憶

尾部操作

pop() 刪除陣列最後的一個元素並且返回

引數: 無

push(item1, item2...) 陣列的末尾新增元素並返回新長度

引數:要新增的新元素

// 刪除
var a = [1, 3, 5, 7, 9]
a.pop() // [1, 3, 5, 7]
// 新增
a.push(9, 11)
// [1, 3, 5, 7, 9, 11]

頭部操作

shift() 刪除陣列第一個元素並返回

引數: 無

unshift(item1, item2...) 陣列頭部新增元素並返回新長度

引數:要新增的新元素

// 刪除
var a = [1, 3, 5, 7, 9]
a.shift() // [1, 3, 5, 7]
// 新增
a.unshift(0) // [0, 1, 3, 5, 7]
reverse() 顛倒陣列中元素的順序

引數: 無

let  a =  [1,2,3]
a.reverse()
console.log(a)  // [3,2,1]

下面是 ES6 新增的兩個方法

fill(item, start, end) 用指定元素填充陣列

引數:

item(必需): 要填充陣列的值

start(可選): 填充的開始位置,預設值為0

end(可選):填充的結束位置,預設是為this.length

['a', 'b', 'c'].fill(7)
// [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
copyWithin(target, start, end) 指定位置的成員複製到其他位置並返回替換後的新陣列。

引數:

target(必需):從該位置開始替換資料。如果為負值,表示倒數。

start(可選):從該位置開始讀取資料,用哪些資料來替換,預設為 0。如果為負值,表示倒數。

end(可選):到該位置前停止讀取資料,預設等於陣列長度。使用負數可從陣列結尾處規定位置。


 [1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]

var a=['a','b','c','d','e','f','g','h','i','j']
// 2位置開始被替換,3位置開始讀取要替換的 5位置前面停止替換
a.copyWithin(2,3,5)
// ["a","b","d","e","e","f","g","h","i","j"]

這裡可以總結下:

  1. 替換前後陣列的長度保持不變;

  2. 讀取資料在終止位置的前一個位置停止,並且儲存這個位置的資料不動

  3. 讀取出來了多少資料,就需要在前面按順序替換掉多少資料。

上面大類屬於可以改變原陣列的例項方法,下面一大類當然就是不改變原陣列了。

不改變原陣列(8個)

slice(start, end) 擷取陣列片段,返回新陣列

引數:

start:(可選)規定從何處開始選取,負數表示從陣列尾部算起

end: (可選)沒指定則一直擷取到陣列最後一個元素,包括最後一個。指定了則擷取到指定位置前一個元素。

[1, 2, 3, 4].slice()
//  [1, 2, 3, 4]
[1, 2, 3, 4].slice(1)
// [2, 3, 4]
[1, 2, 3, 4].slice(1, 3)
// [2, 3]
join(str) 按照連線符將陣列連線成字串並返回字串

引數:

沒有引數: 則使用 , 連線

有引數: 按照引數指定連線符連線


let a= ['hello','world']
let str=a.join()  // 'hello,world'
let str2=a.join('+')  // 'hello+world'

特別注意:當原始陣列中含有物件時,使用 join() 方法連線時會把物件轉成 [object Object]字串,看下面:


var b = [{name: 'pubdreamcc', age: 24}, 'test']
b.join()
// [object Object],test
cancat(item1,item2...) 合併多個陣列並返回

引數:

可以是陣列物件:等待合併的陣列

也可以是具體的值(元素): 等待合併的元素


var a = [1, 2, 3]
var b = [4, 5, 6]
a.concat(b)
// [1, 2, 3, 4, 5, 6]

a.concat(4, 5, 6)
// [1, 2, 3, 4, 5, 6]
toLocaleString() 陣列轉字串

引數: 無

該方法同樣也是陣列轉字串,是將陣列中每一個元素呼叫自身的toLocaleString() 方法後用 , 連線得到的字串。

可以理解為先把陣列中每個元素都呼叫下 toLocaleString() 方法,再把得到的結果陣列呼叫 join() 方法。

let a=[{name:'pubdreamcc'},24,'cc',new Date()]
a.toLocaleString()
// [object Object],24,cc,2019/7/18 下午1:52:20
toString() 陣列轉字串

這個方法應該比較熟悉,它是定義在 Object 原型上面的一個方法,用來把一個物件轉成字串,在這裡其實同 join(無引數) 方法效果一樣。

實際開發中不推薦使用。

indexOf(item, start) 查詢陣列某個元素並返回其第一次出現位置下標

引數:

item(必需): 需要查詢的元素值

start(可選): 規定在陣列中開始檢索的位置(0-array.length)

如果沒找到,返回 -1

var a = [1, 2, 1]
a.indexOf() // -1
a.indexOf(1) // 0
a.indexof('1') // -1

注意: indexOf()不能識別NaN, 因為 NaN 與任何數不相等,包括自身。

lastIndexOf(item, fromIndex) 查詢陣列某個元素並返回其最後一次出現位置下標

該方法與 indexOf() 恰好相反,查詢不到同樣返回 -1

引數:

item(必需): 被查詢的元素

fromIndex(可選): 逆向查詢開始位置,預設值陣列的長度-1,即查詢整個陣列。


 let a=['cc',4,'pubdreamcc',1,2,'pubdreamcc',3,4,5,'pubdreamcc'] // 陣列長度為10
 // let b=a.lastIndexOf('pubdreamcc',4) // 從下標4開始往前找 返回下標2
 // let b=a.lastIndexOf('pubdreamcc',100) //  大於或陣列的長度 查詢整個陣列 返回9
 // let b=a.lastIndexOf('pubdreamcc',-11) // -1 陣列不會被查詢
 let b=a.lastIndexOf('pubdreamcc',-9) // 從第二個元素4往前查詢,沒有找到 返回-1

下面這個方法是 ES7 中新增

includes(item, fromIndex) 查詢陣列是否包含某個元素返回布林

引數:

item (必需):要查詢的元素

fromIndex (可選): 預設值為0,參數列示搜尋的起始位置,接受負值。正值超過陣列長度,陣列不會被搜尋,返回false。負值絕對值超過長陣列度,重置從0開始搜尋。

注意: includes()方法可以檢測 NaN

let a=['cc','pubdreamcc',1,NaN]
// let b=a.includes(NaN) // true 識別NaN
// let b=a.includes('pubdreamcc',100) // false 超過陣列長度 不搜尋
// let b=a.includes('pubdreamcc',-3)  // true 從倒數第三個元素開始搜尋
// let b=a.includes('pubdreamcc',-100)  // true 負值絕對值超過陣列長度,搜尋整個陣列

總結完了陣列的基本兩大類方法後,接下來我們開始上陣列的遍歷方法。

遍歷方法 (12個)

陣列的遍歷也是非常重要,在實際專案開發中用的很多,不同的場景使用不同的遍歷方法可以加快我們開發速度。

陣列的遍歷並不會改變原始陣列。

forEach(func, thisValue) 遍歷陣列,為每一項執行一次回撥函式

引數:

func(必需):指定的回撥函式

thisValue(可選):當執行回撥函式時this繫結物件的值,預設值為undefined

array.forEach((value, index, arr) => {}, thisValue)

關於 forEach() 這裡需要注意的幾點:

  1. 無法中途退出迴圈,只能用return退出本次回撥,進行下一次回撥。

  2. 它總是返回 undefined值,即使你return了一個值。

  3. 如果在回撥中需要更改陣列中的基本型別資料,請使用 array[index] = XXX,不能直接給 value 賦值。

every(func, thisValue) 檢測陣列所有元素是否都符合判斷條件返回布林

引數:

func(必需):指定的回撥函式

thisValue(可選):當執行回撥函式時this繫結物件的值,預設值為undefined

如果有一項元素執行回撥返回false,剩餘元素不再執行回撥,整個方法返回 false

如果所有元素都滿足條件,則整個方法返回 true

[12, 5, 8, 130, 44].every(x => x >= 10) // 判斷陣列中每個元素是否大於或等於 10
// false
some(func, thisValue) 檢測陣列中的是否有滿足條件的元素返回布林

引數:

func(必需):指定的回撥函式

thisValue(可選):當執行回撥函式時this繫結物件的值,預設值為undefined

some() 恰好和 every() 相反,只要陣列中有一項滿足條件判斷,則整個方法返回 true,如果全部元素都不滿足條件,則返回 false

[12, 5, 8, 130, 44].every(x => x >= 10) // 判斷陣列中是否有元素大於或等於 10
// true
filter(func, thisValue) 按照條件過濾原始陣列返回新陣列

引數:

func(必需):指定的回撥函式

thisValue(可選):當執行回撥函式時this繫結物件的值,預設值為undefined

var arr1 = [1, 3, 8, 4, 6, 7, 2]
var arr2 = arr1.filter((item, index)=>{return item > 5})
// 從原陣列中過濾出大於 5 的元素
// [6, 7, 8]
map(func, thisValue) 對陣列中每個元素進行一次回撥,返回回撥返回的元素組成的陣列

引數:

func(必需):指定的回撥函式

thisValue(可選):當執行回撥函式時this繫結物件的值,預設值為undefined

可以發現這個幾個方法的引數都一樣,只是返回值不同而已

let a1 = ['1','2','3','4']
let a2 = a1.map((value, index) => {
  return +value
})
// [1, 2, 3, 4]
reduce(func, initialValue) 為陣列提供一個累加器,把陣列合併為一個值

reduce() 方法很多人搞的不是很清楚,也包括自己,講真的這個方法還真有點繞,但是弄明白之後確實可以給我們帶來很多的便利。

引數:

func(必需):指定的回撥函式

initialValue(可選):傳遞給回撥的初始值,說白了即是回撥第一個引數 prev 的初始值。

func(prev, curr, currIndex, arr)

引數解析:

prev(必需): 函式上一次 return 回來的值。如果提供了 initialValue,則初始值為initialValue,如果沒有提供,則 prev初始值為陣列第一個元素。

curr(必需): 當前執行回撥時,陣列中的元素

currIndex(可選): 當前執行回撥時,陣列中元素的下標

arr(可選):當前元素所屬的陣列物件

利用 reduce() 方法 我們運算元組更加方便,例如一些常見的例子:

  1. 陣列元素求和
var arr = [1, 3, 5, 7, 9]
var sum = arr.reduce((prev, curr) => {
  return prev+curr
})
// 25
  1. 統計陣列中元素出現的次數
var arr = ['cc', 'cc1', 'cc', 'cc2', 'cc1', 'cc', 'cc5']
var obj = arr.reduce((prev, curr) => {
  if (!prev[curr]) {
    prev[curr] = 1
  } else {
    prev[curr] += 1
  }
  return prev
}, {})

// {'cc': 3, 'cc1': 2, 'cc2': 1, 'cc5': 1}
reduceRight(func, initialValue) 從右至左的方向把陣列累加為一個值

該方法同上面講的 reduce() 方法使用基本一致,只不過累加的方式為陣列的末尾向前將陣列中的陣列項做累加。

下面幾個關於遍歷的方法是 ES6 新增的,一種關於查詢,一種是關於遍歷。

find(func, thisValue) 找出第一個符合條件的陣列成員並返回

引數:

func(必需):指定的回撥函式

thisValue(可選):當執行回撥函式時this繫結物件的值,預設值為undefined

如果沒有找到,則返回 undefined

var arr = [1, 3, 5, 7]
var num = arr.find((item, index) => {return item > 1})
// 3
findIndex(func, thisValue) 找出第一個符合條件的陣列成員下標並返回

引數:

func(必需):指定的回撥函式

thisValue(可選):當執行回撥函式時this繫結物件的值,預設值為undefined

如果沒有找到則返回 -1

var arr = [1, 3, 5, 7]
var index = arr.findIndex((item, index) => {return item > 1})
// 1

注意:

這兩個方法都可以識別 NaN,彌補了indexOf 的不足

keys()&values()&entries() 遍歷鍵名、遍歷鍵值、遍歷鍵名+鍵值

這三種方法都會返回一個新的 Array Iterator 物件

array.keys() 返回一個包含陣列所有下標組成的 Iterator。

array.values() 返回一個包含陣列所有元素組成的 Iterator。

array.entries() 返回一個包含陣列元素加下標組成的 Iterator。

返回的 遍歷器 可以用 ES6 提供的 for...of 迴圈來遍歷。

for (let index of ['pubdreamcc', 'pubdreamcc1'].keys()) {
  console.log(index)
}
// 0
// 1

for (let item of ['pubdreamcc', 'pubdreamcc1'].values()) {
  console.log(item)
}
// 'pubdreamcc'
// 'pubdreamcc1'

for (let [index, item] of ['pubdreamcc', 'pubdreamcc1'].entries()) {
  console.log(index, item)
}
// 0 "pubdreamcc"
// 1 "pubdreamcc1"

結語

花了將近一下午的時間來整理出陣列的一些方法,希望自己能夠更加清晰包括理解 它們 的用法,當然最最重要還是在平時擼碼的過程中能夠運用到對的地方加快開發效率,畢竟我們們學技術還是要服務於產品,把技術變現呢。

最後,希望你能夠細心看完,保證你會有不一樣的收穫。

參考資料

阮一峰 ES6 陣列擴充套件

路易斯 [深度長文]JavaScript陣列所有API全解密

相關文章