javascript中陣列的回顧

weixin_33840661發表於2017-12-14

陣列在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;

寫這篇文章主要是對自己學習陣列做一個總結。如果對上面的問題有更好的解答,歡迎留言告知。

相關文章