陣列在javascript中使用度非常頻繁,我總結了一些在陣列中很常見的問題。
關於陣列中的方法非常多,我總結了一張表來大致瞭解陣列中的方法
Array中的方法 | 含義 | 改變原陣列 | 返回值 | ES6新增 |
---|---|---|---|---|
concat | 合併兩個或多個陣列 | false | 新陣列 | false |
copyWithin | 淺複製陣列的一部分到同一陣列中的另一個位置 | true | 改變後的陣列 | true |
entries | 返回陣列迭代器物件,該物件包含陣列中每個索引的鍵/值對 | false | 陣列迭代器 | true |
every | 測試陣列的所有元素是否都通過了指定函式的測試 | false | 布林值,true/false | false |
fill | 用一個固定值填充一個陣列中從起始索引到終止索引內的全部元素 | true | 改變後的陣列 | true |
filter | 建立一個新陣列, 其包含通過所提供函式實現的測試的所有元素 | false | 新陣列 | false |
find | 返回陣列中滿足提供的測試函式的第一個元素的值。否則返回undefined | false | javascript語言型別 | true |
findIndex | 返回陣列中滿足提供的測試函式的第一個元素的索引。否則返回-1 | false | 陣列索引 | true |
forEach | 遍歷陣列 | false | undefined | false |
includes | 判斷一個陣列是否包含一個指定的值 | false | 布林值,true/false | true |
indexOf | 返回在陣列中可以找到一個給定元素的第一個索引,如果不存在,則返回-1 | false | 陣列索引 | false |
join | 將陣列(或一個類陣列物件)的所有元素連線到一個字串中 | false | 字串 | false |
keys | Array迭代器,它包含陣列中每個索引的鍵 | false | 陣列迭代器 | true |
lastIndexOf | 返回指定元素在陣列中的最後一個的索引,如果不存在則返回 -1 | false | 陣列索引 | false |
map | 遍歷陣列 | false | 新陣列 | false |
pop | 從陣列中刪除最後一個元素,並返回該元素的值 | true | 陣列元素 | false |
push | 將一個或多個元素新增到陣列的末尾,並返回新陣列的長度 | true | 陣列長度 | false |
reduce | 對累加器和陣列中的每個元素(從左到右)應用一個函式,將其減少為單個值 | false | 函式返回值 | false |
reduceRight | reduce執行方向相反,從右到左 | false | 函式返回值 | false |
reverse | 將陣列中元素的位置顛倒 | true | 改變後的陣列 | false |
shift | 從陣列中刪除第一個元素,並返回該元素的值 | true | 陣列元素 | false |
slice | 可從已有的陣列中返回選定的元素 | false | 新陣列 | false |
some | 測試陣列中的某些元素是否通過由提供的函式實現的測試 | false | 布林值,true/false | false |
sort | 在適當的位置對陣列的元素進行排序 | true | 一個新陣列 | false |
splice | 刪除現有元素和/或新增新元素來更改一個陣列的內容 | true | 刪除的元素陣列 | false |
toLocaleString | 返回一個字串表示陣列中的元素 | false | 字串 | false |
toString | 返回一個字串,表示指定的陣列及其元素 | false | 字串 | false |
unshift | 將一個或多個元素新增到陣列的開頭 | true | 陣列長度 | false |
values | 一個陣列迭代器物件,該物件包含陣列每個索引的值 | false | 陣列迭代器 | true |
從這個表中我們要小心幾個方法,reverse和sort會改變原陣列,並返回改變的新陣列,push和unshift方法返回的是陣列長度而不是陣列,forEach方法返回的是undefined不是陣列。
此外,我還需提一下slice和splice這兩個方法,說實話這兩個方法看起來很像,容易讓人搞混,最關鍵的是用到的頻率還蠻高的,這兩個方法就像字串中substr和substring這兩個老兄弟,閒著沒事就喜歡去迷惑別人,本人就曾深深的被這兩個方法傷害過。
slice接受兩個引數start和end,代表需要擷取的陣列的開始序號和結束序號。
var arr = [4,3,5,8,9,6];
arr.slice(0) // [4,3,5,8,9,6],end可以省略,預設為陣列長度
arr.slice(0,4) //[4,3,5,8]
arr.slice(-1); //[6], start為負數代表從陣列擷取的開始序號從尾部算起
arr.slice(0,-1); //[4,3,5,8,9] end為負數表示結束序號從尾部算起
arr.slice(2,0); //[]
arr.slice(-1,-1); //[] 如果start和end符號相同,end一定大於start,否則返回的會是[]
splice的引數為index,deleteCount和...items,index表示需要刪除或新增原數時的位置,負數表示從尾部算起,deleteCount表示要刪除的元素,0表示不刪除。其中items表示新增的元素個數。
var arr = [4,3,5,8,9,6];
arr.splice(0,0) //返回[], arr=[4,3,5,8,9,6];
arr.splice(0,2) //返回[4,3], arr=[5,8,9,6];
arr.splice(0,2,3,4) //返回[5,8], arr=[3,4,9,6];
splice不管是新增還是刪除元素,返回的都是刪除元素的列表,splice是先做刪除操作,後新增
var arr = [4,3,5];
arr.splice(3,1,8,9); //返回[], arr= [4, 3, 5, 8, 9];
//如果index大於陣列長度,那麼splice不會刪除元素
注意:雖然slice和splice都返回一個新的陣列,但是slice不會改變原陣列,splice會改變原陣列,這個區別非常關鍵。
最後在加一些經常會問到的陣列問題。
1.建立陣列
//陣列字面量建立
var arr = [1,2];
//Array構造器建立;
var arr = Array(1,2); //[1,2] 可以用new操作符,也可以不用
//Array構造器有個侷限性,不能建立只有單個數字的陣列
var arr = Array(10) //建立的是一個長度為10的空陣列,並不是[10]
//如果傳入的不是Number型別的數字,那麼沒有任何問題
var arr = Array('10') //['10']
//此時如果要建立只有單個數字的陣列,可以用Array.of方法
var arr = Array.of(10) //[10]
var arr = Array.of(1,2) //[1,2]
//Array.from( items [ , mapfn [ , thisArg ] ] )
//items是個可迭代物件,mapfn是遍歷該迭代物件的function,thisArg是mapfn中的this物件
var arr = Array.from([1,2,3]) //[1,2,3]
Array.from是非常有用的建立陣列方法,能把字串轉化為陣列,Map,Set也能轉成陣列。
Array.from('abc') //['a','b','c'];
Array.from(new Set([1,2,3])) //[1,2,3],當然這個例子毫無意義
Array.from(new Map([[1,2],[3,4]])) //[[1,2],[3,4]]
我們知道用Array構造器建立的陣列是個空陣列,map,forEach方法並不能遍歷這個陣列。
var arr = Array(10);
arr.forEach((item,index) => console.log(index)) //不會有輸出
//map,forEach迴圈判斷的是該物件上有沒有對應的屬性
arr.hasOwnProperty(0) //false,以hasOwnProperty為判斷標準
//Array.from中的mapfn方法是以迭代方式來判斷的,因此
Array.from(arr,(item,index)=>console.log(index)) //0,1,2,3,4,5,6,7,8,9
由於這個原因,我們可以快速對陣列初始化,比如建立一個0到99的陣列
Array.from(Array(100),(item,index)=>index);
//當然,如果你用到上表中Array的keys方法那更快捷
Array.from(Array(100).keys());
2.陣列去重
方法一,建立物件的鍵值唯一性來進行去重:
var arr = [1,2,3,1,3,5,3,2];
var _arr = [];
var obj = {};
arr.forEach(item => {
if(!obj[item]){
_arr.push(item);
obj[item] = true;
}
})
arr = _arr;
方法二,結合Set的鍵值唯一性以及Array.from方法可以快速陣列去重:
var arr = Array.from(new Set([1,2,3,1,3,5,3,2])) //[1,2,3,5]
3.快速複製一個陣列
var arr = [1,2,3,4];
var arr1 = arr.slice();
var arr2 = arr.concat();
注:這裡的複製指的是淺拷貝
4.求陣列最大值,最小值
這裡的陣列指的是全是數字的陣列
方法一,sort排序後取值
var arr = [1,4,6,2,33,19,6,9];
var maxvalue = arr.sort((a,b) => b>a )[0]
var minvalue = arr.sort((a,b) => a>b )[0]
方法二,Math的max和min方法呼叫
var arr = [1,4,6,2,33,19,6,9];
var maxvalue = Math.max.apply(null,arr); //33
var minvalue = Math.min.apply(null,arr); //1
5.陣列排序
在不用系統自帶的sort的情況下對陣列排序有很多方法,比如冒泡、插入以及快速排序等。但我總覺得這些排序方法還是過於複雜,有沒有更快以及更方便的排序,我思考了好久,後來先想到了可以用陣列的序號進行排序。原理是把陣列1中的值變成陣列2中的序號:
var arr = [3,4,6,2,8,7,5],
arr2 = [];
arr.forEach(item => arr2[item] = item);
arr = [];
arr2.forEach(item => arr.push(item));
寫完之後自己感覺美滋滋,可之後發現如果陣列中有負數,不就都玩完了嗎。於是趕緊改:
var arr = [3,-4,6,-2,-8,7,5],
parr = [];
narr = [];
arr.forEach(item => item>=0?parr[item] = item:narr[-item] = item);
arr = [];
parr.forEach(item => arr.push(item));
narr.forEach(item => arr.unshift(item));
注:如果陣列中有重複數字則排序方法有誤,會把重複數字去掉。
寫完之後發現其實也沒有比冒泡、插入以及快速排序的方法快多少。
6.求一個整數陣列是否包含另一個整數陣列
一開始我想到一個方法,把兩個陣列轉換成字串,在進行includes或者indexOf判斷就可以了,後來我發現了問題:
var a = [2,4,8,6,12,67,9];
var b = [8,6,12];
a.join(',').includes(b.join(',')); //true; 這是可以的
var b = [8,6,1]
a.join(',').includes(b.join(',')); //true; 這居然也可以,顯然有問題
//於是改成
a.join(',').includes(','+b.join(',')+','); //false;
//後來我又發現如果b陣列在a陣列的開頭和結尾都會有問題,於是又改成如下:
(','+a.join(',')+',').includes(','+b.join(',')+','); //false;
寫這篇文章主要是對自己學習陣列做一個總結。如果對上面的問題有更好的解答,歡迎留言告知。