【相關推薦:、】
上篇介紹了陣列的基本概念和一些簡單的陣列元素操作函數,實際上,陣列提供的函數還有很多。
push
、pop
、shift
和unshift
是運算元組首尾兩端的函數,上文已經講過,本文不再贅述。
上篇已經簡單介紹過,陣列就是一個特殊的物件,因此我們可以嘗試使用物件的屬性刪除方法:delete
。
舉個例子:
let arr = [1,2,3,4,5];delete arr[2];console.log(arr);
程式碼執行結果如下:
注意觀察圖中標黃的位置,雖然元素被刪除了,但是陣列的長度仍然是5
,而且刪除掉的位置多了一個空
。如果我們存取下標為2
的元素,會得到如下的結果:
造成這種現象的原因是,delete obj.key
是通過key
移除對應值的,也就是說delete arr[2]
刪除了陣列中的2:3
鍵值對,當我們存取下標2
時,就是undefined
了。
而在陣列中,我們常常希望刪除元素後,元素的位置會被後繼的元素填補,陣列的長度變短。
這個時候,我們就需要splice()
方法。
需要提前說明的是,splice()
方法的功能相當豐富,並非只能刪除元素,以下是語法:
arr.splice(start[,deleteCount,e1,e2,...,eN])
splice
方法從start
位置開始,刪除deleteCount
個元素,然後原地插入e1,e2,e3
等元素。
以下範例可以從陣列中刪除一個元素:
let arr = [1,2,3,4,5]arr.splice(0,1);//刪除掉第一個元素1console.log(arr)
以上程式碼刪除陣列中第一個位置的1
個元素,執行結果如下:
刪除多個元素和刪除一個元素用法相同,只需要將第二個引數改為指定數量就可以了,舉例如下:
let arr = [1,2,3,4,5];arr.splice(0,3);//刪除前三個元素console.log(arr);//[4,5]
程式碼執行結果如下:
如果我們只提供一個引數start
,那麼就會刪除陣列start
位置後面的所有元素,舉個例子:
let arr = [1,2,3,4,5]arr.splice(2);//刪除從下標為2以及後面的所有元素console.log(arr);//[1,2]
程式碼執行結果:
如果我們提供了超過兩個引數,那麼就可以替換陣列元素,舉個例子:
let arr = [1,2,3,4,5];arr.splice(0,2,'itm1','itm2','itm3');console.log(arr);//['itm1','itm2','itm3',3,4,5]
程式碼執行結果如下:
以上程式碼實際上執行了兩步操作,首先刪除從0
開始的2
個元素,然後在0
位置插入三個新的元素。
如果我們把第二個引數(刪除數量)改為0
,那麼就可以只插入元素,不刪除元素,舉個栗子:
let arr = [1,2,3,4,5]arr.splice(0,0,'x','y','z')console.log(arr);//['x','y','z'1,2,3,4,5]
splice()
函數會返回被刪除的元素陣列,舉個例子:
let arr = [1,2,3,4,5]let res = arr.splice(0,3,'x','y')console.log(arr)//['x','y',4,5]console.log(res)//[1,2,3]
程式碼執行結果:
我們可以使用負數指示開始操作元素的位置,舉個例子:
let arr = [1,2,3,4,5]arr.splice(-1,1,'x','y','z')console.log(arr)//[1,2,3,4,'x','y','z']
程式碼執行結果如下:
slice()
方法可以擷取指定範圍的陣列,語法如下:
arr.slice([start],[end])
返回一個新陣列,新陣列從start
開始,到end
結束,但是不包括end
。
舉例:
let arr = [1,2,3,4,5]console.log(arr.slice(2,5))//[3,4,5]console.log(arr.slice(1,3))//[2,3]
程式碼執行結果:
slice()
同樣可以使用負數下標:
let arr = [1,2,3,4,5]console.log(arr.slice(-3))//[3,4,5]console.log(arr.slice(-5,-1))//[1,2,3,4]
程式碼執行結果如下:
如果只為slice()
方法提供一個引數,就會和splice()
一樣截斷到陣列末尾。
concat()
函數可以將多個陣列或者其他型別的值拼接稱一個長陣列,語法如下:
arr.concat(e1, e2, e3)
以上程式碼將返回一個新的陣列,新陣列由arr
拼接e1
、e2
、e3
而成。
舉例:
let arr = [1,2,3]console.log(arr.concat([4,5],6,7,[8,9]))
程式碼執行結果如下:
普通的物件,即使它們看起來和物件一樣,仍然會被作為一個整體插入到陣列中,例如:
let arr = [1,2]let obj = {1:'1',2:2}console.log(arr.concat(obj))
程式碼執行結果:
但是,如果物件具有Symbol.isConcatSpreadable
屬性,就會被當作陣列處理:
let arr = [1,2]let obj = {0:'x', 1:'y', [Symbol.isConcatSpreadable]:true, length:2 }console.log(arr.concat(obj))
程式碼執行結果:
遍歷整個陣列,為每個陣列元素提供一個操作函數,語法:
let arr = [1,2]arr.forEach((itm,idx,array)=>{ ...})
應用舉例:
let arr = [1,2,3,4,5]arr.forEach((itm)=>{ console.log(itm)})
程式碼執行結果:
let arr = [1,2,3,4,5]arr.forEach((itm,idx,array)=>{ console.log(`arr[${idx}] in [${array}] is ${itm}`)})
程式碼執行結果:
類似於字串,indexOf
、lastIndexOf
、includes
可與查詢陣列中指定元素的下標:
arr.indexOf(itm,start)
:從start
位置開始搜尋itm
,如果找到返回下標,否則返回-1
;arr.lastIndexOf(itm,start)
:倒序查詢整個陣列,直至start
處,返回第一個查到的下標(也就是陣列最後一個匹配項),找不到返回-1
;arr.includes(itm,start)
:從start
位置開始搜尋itm
,找到返回true
,否則返回false
;舉例:
let arr = [1,2,3,4,5,6,"7","8","9",0,0,true,false]console.log(arr.indexOf(0))//9console.log(arr.lastIndexOf(0))//10console.log(arr.includes(10))//falseconsole.log(arr.includes(9))//false
這些方法在比較陣列元素的時候使用的是===
,所以false
和0
是不一樣的。
NaN的處理
NaN
是一個特殊的數位,三者在處理NaN
有細微差別:
let arr = [NaN,1,2,3,NaN]console.log(arr.includes(NaN))//trueconsole.log(arr.indexOf(NaN))//-1console.log(arr.lastIndexOf(NaN))//-1
產生這種結果的原因和NaN
本身的特性有關,即NaN
不等於任何數位,包括他自己。
這些內容在前面的章節已經講過了,遺忘的童鞋記得溫故知新呀。
在程式設計過程中常常會遇到物件陣列,而物件是不能直接使用===
比較的,如何從陣列中查詢到滿足條件的物件呢?
這個時候就要使用find
和findIndex
方法,語法如下:
let result = arr.find(function(itm,idx,array){ //itm陣列元素 //idx元素下標 //array陣列本身 //傳入一個判斷函數,如果該函數返回true,就返回當前物件itm})
舉個栗子,我們查詢name
屬性等於xiaoming
的物件:
let arr =[ {id:1,name:'xiaoming'}, {id:2,name:'xiaohong'}, {id:3,name:'xiaojunn'},]let xiaoming = arr.find(function(itm,idx,array){ if(itm.name == 'xiaoming')return true;})console.log(xiaoming)
程式碼執行結果:
如果沒有符合條件的物件,就會返回undefined
。
以上程式碼還可以簡化為:
let xiaoming = arr.find((itm)=> itm.name == 'xiaoming')
執行效果是完全相同的。
arr.findIndex(func)
的用途和arr.find(func)
幾乎相同,唯一不同的地方在於,arr.findIndex
返回符合條件物件的下標而不物件本身,找不到返回-1
。
find
和findIndex
只能查詢一個滿足要求的物件,如果一個陣列中存在多個滿足要求的物件,就需要使用filter
方法,語法如下:
let results = arr.filter(function(itm,idx,array){ //和find的用法相同,不過會返回符合要求的物件陣列 //找不到返回空陣列})
舉個例子:
let arr =[ {id:1,name:'xiaoming'}, {id:2,name:'xiaohong'}, {id:3,name:'xiaojunn'},]let res = arr.filter(function(itm,idx,array){ if(itm.name == 'xiaoming' || itm.name == 'xiaohong')return true;})console.log(res)
程式碼執行結果:
arr.map
方法可以對陣列的每個物件都呼叫一個函數,然後返回處理後的陣列,這是陣列最有用的、最重要的方法之一。
語法:
let arrNew = arr.map(function(itm,idx,array){ //返回新的結果})
舉例,返回字串陣列對應的長度陣列:
let arr = ['I','am','a','student']let arrNew = arr.map((itm)=>itm.length)//return itm.lengthconsole.log(arrNew)//[1,2,1,7]
程式碼執行結果:
arr.sort
對陣列進行原地排序,並返回排序後的陣列,但是,由於原陣列已經發生了改變,返回值實際上沒有什麼意義。
所謂原地排序,就是在原陣列空間內排序,而不是新建一個陣列
let arr = ['a','c','b']arr.sort()console.log(arr)
程式碼執行結果:
注意,預設情況下
sort
方法是以字母序進行排序的,也就是適用於字串排序,如果要排列其他型別的陣列,需要自定義比較方法
數位陣列
let arr = [1,3,2]arr.sort(function(a,b){ if(a > b)return 1; if(a < b)return -1; return 0;})
程式碼執行結果:
sort
函數內部採用了快速排序演演算法,也可能是timsort
演演算法,但是這些我們都不需要關心,我們只需要關注比較函數就可以了。
比較函數可以返回任何數值,正數表示>
,負數表示<
,0
表示等於,所以我們可以簡化數位比較方法:
let arr = [1,3,2]arr.sort((a,b)=> a - b)
如果想要逆序排列只需要交換一下a
和b
的位置既可以了:
let arr = [1,3,2]arr.sort((a,b)=> b - a)
字串排序
別忘了字串比較要使用str.localeCompare(str1)
方法呦
let arr = ['asdfas','success','failures']arr.sort((a,b)=>a.localeCompare(b))
程式碼執行結果:
arr.reverse
用於逆序陣列
let arr = [1,2,3]arr.reverse()console.log(arr)//[3,2,1]
這個沒啥好說的。
還記得字串分割函數嗎?字串分割函數可以將字串分割成一個字元陣列:
let str = 'xiaoming,xiaohong,xiaoli'let arr = str.split(',')//['xiaoming','xiaohong','xiali']
冷門知識,
split
函數有第二個引數,可以限制生成陣列的長度let str = 'xiaoming,xiaohong,xiaoli'let arr = str.split(',',2)//['xiaoming','xiaohong']
arr.join()
方法用途和split
方法相反,可以將一個陣列組合成一個字串。
舉個栗子:
let arr = [1,2,3]let str = arr.join(';')console.log(str)
程式碼執行結果:
arr.reduce
方法和arr.map
方法類似,都是傳入一個方法,然後依次對陣列元素呼叫這個方法,不同的地方在於,app.map
方法在處理陣列元素時,每次元素呼叫都是獨立的,而arr.reduce
會把上一個元素的呼叫結果傳到當前元素處理方法中。
語法:
let res = arr.reduce(function(prev,itm,idx,array){ //prev是上一個元素呼叫返回的結果 //init會在第一個元素執行時充當上一個元素呼叫結果},[init])
試想一下,如何實現一個數位組成的陣列元素和呢?map是沒有辦法實現的,這個時候就需要使用arr.reduce
:
let arr = [1,2,3,4,5]let res = arr.reduce((sum,itm)=>sum+itm,0)console.log(res)//15
程式碼執行過程如下圖:
arr.reduceRight
和arr.reduce
用途相同,只不過從右往左對元素呼叫方法。
陣列是物件的一種特例,使用typeof
無法準確的分辨二者的區別:
console.log(typeof {})//objectconsole.log(typeof [])//object
二者都是物件,我們需要使用Array.isArray()
方法進一步做判斷:
console.log(Array.isArray({}))//falseconsole.log(Array.isArray([]))//true
arr.some(func)
和arr.every(func)
方法用於檢查數位,執行機制和map
類似。
some
對每個陣列元素執行傳入的方法,如果方法返回true
,立即返回true
,如果所有的元素都不返回true
,就返回false
。
every
對陣列的每個元素執行傳入的方法,如果所有元素都返回true
,則返回true
,否則返回false
。
舉個例子:
let arr = [1,2,3,4,5]//判斷陣列是否存在大於2的元素console.log(arr.some((itm)=>{ if(itm > 2)return true;}))//true//判斷是否所有的元素都大於2console.log(arr.every((itm)=>{ if(itm > 2)return true;}))//false
在所有的陣列方法中,除了sort
,都有一個不常用固定引數thisArg
,語法如下:
arr.find(func,thisArg)arr.filter(func,thisArg)arr.map(func,thisArg)
如果我們傳入了thisArg
,那麼它就會在func
中變為this
。
這個引數在常規情況下是沒什麼用處的,但是如果func
是一個成員方法(物件的方法),而且方法中使用了this
那麼thisArg
就會非常有意義。
舉個例子:
let obj = { num : 3, func(itm){ console.log(this) return itm > this.num;//查詢大於3的數位 }}let arr = [1,2,3,4,5,6,7]let newArr = arr.filter(obj.func,obj)console.log(newArr)
程式碼執行結果:
這裡我們可以看到,func
中輸出的this
就是我們傳入的thisArg
值。
如果我們使用物件成員方法,同時不指定thisArg
的值,就會造成this
為undefined
,從而導致程式錯誤。
【相關推薦:、】
以上就是JavaScript陣列操作函數總結分享的詳細內容,更多請關注TW511.COM其它相關文章!