javascript
js map 排序_数组方法写给女友的一系列 JS 数组操作(建议收藏 | 内附思维导图)...
前言
最近和女友,咳咳...(說出來可能會被打s)學習JS數組方法,用幾個字形容的話就是聽說過,實際使用、遇到的時候就分不清具體方法會得到怎樣的結果。
今天我將通過這篇文章好好整理一下關于JS數組的方法,讓大家通過這一篇文章 掌握 數組一系列操作,同時,在面試或者工作的時候也能寫出簡潔、優雅、美觀、高效的代碼。其次,這篇寫給女友,她看到會感動到哭嘛?會嗎會嗎會嗎?
話說我有女友嗎?
啊這,這...這重要嗎?
(手機端可能看不清)獲取高清PDF,請在微信公眾號【小獅子前端Vue】回復【數組方法】
閱讀須知
開門見山,我先介紹一下本文整體目錄結構,介紹我將輸出的大概內容。
顯然,數組的方法有很多很多,但是實際工作或者面試過程中有些用到的少之又少,因此,我不會將所有的方法都提出來,然后解析。那么,我會將重要程度比較高的方法盡量用詳細簡潔的語言帶過,同時例舉幾個樣例,自測案例為你加深鞏固。
其次,本文還會提及面試??紗栴},比如經典「扁平化」問題,數組「去重」、「合并」、排序、「改變原數組的方法」、「不改變原數組」的方法等等。
好了,讓我們進入正文~
數組的遍歷
猶記得今年快手面試官就問了一道經典面試題:說說你所知道的數組的遍歷方法?
我想這個問題小伙伴們面試時應該也會遇到過吧,面試官問這個問題其一就是考察你對數組方法掌握程度,其二可以通過你說的方法選擇其中一個繼續深度詢問,比如 reduce、map使用等等,因此,我將 「數組遍歷」 作為第一個模塊來講解。
for 循環
let?arr?=?[1,?2,?3,?4,?5];for?(let?i?=?0;?i???console.log(arr[i]);
}
//?1
//?2
//?3
//?4
//?5
for..of 循環
摘自MDN上一句話,for...of 語句遍歷「可迭代對象」定義要迭代的數據。簡單來說,for...of遍歷的就是 value。
let?arr?=?['Chocolate',?'zhlll',?'lionkk'];for?(let?val?of?arr)?{
??console.log(val);
}
//?Chocolate
//?zhlll
//?lionkk
for...in 循環
摘自MDN上一句話,for...in 語句以任意順序迭代對象的「可枚舉屬性」。簡單來說,for...in遍歷的就是 key。對于數組,key對應著的是數組的「下標索引」。
let?arr?=?['Chocolate',?'zhlll',?'lionkk'];for?(let?key?in?arr)?{
??console.log(key);
}
//?0
//?1
//?2
array.forEach() 方法
先來介紹語法:
array.forEach(callback(currentValue,?index,?arr),?thisArg)callback:為數組中每個元素執行的函數,該函數接收一至三個參數 currentValue 數組中正在處理的當前元素 index (可選) ?數組中正在處理的當前元素的索引 arr (可選) ? ?forEach() 方法正在操作的數組 thisArg ? ? ?可選參數,當執行回調函數callback,用作this值
簡單例子:
let?arr?=?['Chocolate',?'zhlll',?'lionkk'];arr.forEach(function?(cur,?index,?arr)?{
??console.log(cur,?index,?arr);
})
//?Chocolate?0?[?'Chocolate',?'zhlll',?'lionkk'?]
//?zhlll?1?[?'Chocolate',?'zhlll',?'lionkk'?]
//?lionkk?2?[?'Chocolate',?'zhlll',?'lionkk'?]
從上述例子中,了解到 forEach需要傳遞一個回調函數,而那三個參數,后面兩個是可選的,那么如何讓代碼更加優雅美觀一點呢,同時,后面兩個參數按需添加即可:
let?arr?=?['Chocolate',?'zhlll',?'lionkk'];arr.forEach((cur)?=>?{
??console.log(cur);
})
//?Chocolate
//?zhlll
//?lionkk
「疑難點」,我想小伙伴們,應該對最后一個 thisArg 有疑問吧,現在就來解釋一下:
function?Foo()?{??this.sum?=?0;
??this.cnt?=?0;
}
//?在原型上添加一個名為?doSth?方法
Foo.prototype.doSth?=?function?(arr)?{
??arr.forEach(function?(cur)?{
????this.sum?+=?cur;
????this.cnt++;
??},?this)?//?this?指向實例對象
}
let?foo?=?new?Foo();
let?arr?=?[1,?2,?3];
foo.doSth(arr);
console.log(foo.sum,?foo.cnt);
//?6?3
//?解釋:6 ===?(1+2+3)? 3 ===?(1+1+1)
注意:如果使用箭頭函數表達式來傳入函數參數, thisArg 參數會被忽略,因為箭頭函數在詞法上綁定了 this 值。
因此,如果對于普通函數的話,可以看做是將 this 通過傳參的形式解決「無法繼承」 問題,當然,通過箭頭函數的方式是一個不錯的選擇!
map 遍歷
定義:返回一個新數組,其結果是該數組中的每個元素是調用一次提供的回調函數后的返回值。
先來介紹語法:
let?newArray?=?array.map(function(currentValue,?index,?arr),?thisArg)callback:為數組中每個元素執行的函數,該函數接收一至三個參數 currentValue 數組中正在處理的當前元素 index (可選) ?數組中正在處理的當前元素的索引 arr (可選) ? ?map() 方法正在操作的數組 thisArg ? ? ?可選參數,當執行回調函數callback,用作this值
簡單例子:
let?arr?=?['Chocolate',?'zhlll',?'lionkk'];let?newArr?=?arr.map(function?(cur,?index,?arr)?{
??console.log(cur,?index,?arr);
??return?cur?+?index;
})
//?Chocolate?0?[?'Chocolate',?'zhlll',?'lionkk'?]
//?zhlll?1?[?'Chocolate',?'zhlll',?'lionkk'?]
//?lionkk?2?[?'Chocolate',?'zhlll',?'lionkk'?]
console.log(newArr)
//?[?'Chocolate0',?'zhlll1',?'lionkk2'?]
「疑難點」,我想小伙伴們,有了前置問題了,這次理解 thisArg 應該沒有太多問題了吧,看看下面例子:
function?Foo()?{??this.sum?=?0;
??this.cnt?=?0;
}
//?在原型上添加一個名為?doSth?方法
Foo.prototype.doSth?=?function?(arr)?{
??let?newArr?=?arr.map(function?(cur)?{
????this.sum?+=?cur;
????this.cnt++;
????return?cur?+?10;
??},?this)?//?this?指向實例對象
??return?newArr;
}
let?foo?=?new?Foo();
let?arr?=?[1,?2,?3];
console.log(foo.doSth(arr));?//?[?11,?12,?13?]
console.log(foo.sum);//?6
console.log(foo.cnt);//?3
「一些小操作」~
let?arr?=?[1,?4,?9,?16];let?res?=?arr.map(Math.sqrt);?//?傳入Math中sqrt得到數組中每個元素的平方根
console.log(res);?//?[?1,?2,?3,?4?]
「總結」:
- map 不修改調用它的原數組本身(當然可以在 callback 執行時改變原數組) 回調函數不返回值時,最后新數組的每個值都為undefined
- this 的值最終相對于 callback 函數的可觀察性是依據this規則,也就是 this 指向問題
- map 會返回一個新數組
reduce 遍歷
定義:對數組中的每個元素執行一個由您提供的 reducer 函數(升序執行),將其結果匯總為單個返回值。
先來介紹語法:
let?res=?array.reduce(callback(accumulator,?currentValue,?currentIndex,?array),?initialValue)callback:為數組中每個元素執行的函數,該函數接收一至4個參數 accumulator 累計器 currentValue 當前值 currentIndex 當前索引 array 數組 initialValue 作為第一次調用 callback函數時的第一個參數的值。如果沒有提供初始值,則將使用數組中的第一個元素。在沒有初始值的空數組上調用 reduce 將報錯。
簡單例子:
let?arr?=?[3,?5,?7,?1,?2];let?res?=?arr.reduce(function?(acc,?cur,?index,?arr)?{
??console.log(acc,?cur,?index,?arr);
??return?acc?+?cur;
},?0)
//?0?3?0?[?3,?5,?7,?1,?2?]
//?3?5?1?[?3,?5,?7,?1,?2?]
//?8?7?2?[?3,?5,?7,?1,?2?]
//?15?1?3?[?3,?5,?7,?1,?2?]
//?16?2?4?[?3,?5,?7,?1,?2?]
console.log(res);
//?18
看完上面代碼,你可能還是蒙的,怎么一下輸出這么多,結合下面 gif 動圖再來理解一下吧:
「疑難點」,我想小伙伴們對于參數那么多應該一下給看懵了,下面用一些小操作展示一下,并且提供一點自測題目加深鞏固~
let?arr?=?[1,?2,?3,?4,?5];let?res?=?arr.reduce((acc,?cur)?=>?{
??return?acc?+?cur;
},?0)
console.log(res);//?15
自測題:看看下面輸出什么?
[1,?2,?3,?4].reduce((x,?y)?=>?console.log(x,?y));- A: 1 2 and 3 3 and 6 4
- B: 1 2 and 2 3 and 3 4
- C: 1 undefined and 2 undefined and 3 undefined and 4 undefined
- D: 1 2 and undefined 3 and undefined 4
函數接收4個參數:
函數的返回值將會分配給累計器,該返回值在數組的每個迭代中被記住,并最后成為最終的單個結果值。
函數還有一個可選參數, 該參數將作為第一次調用回調函數時的第一個參數的值。如果沒有提供,則將使用數組中的第一個元素。
在上述例子,方法接收的第一個參數(Accumulator)是, 第二個參數(Current Value)是。
在第一次調用時,累加器為,當前值為,打印出累加器和當前值:和。
例子中我們的回調函數沒有返回任何值,只是打印累加器的值和當前值。如果函數沒有返回值,則默認返回。在下一次調用時,累加器為,當前值為“3”, 因此和被打印出。
在第四次調用時,回調函數依然沒有返回值。累加器再次為 ?,當前值為“4”。和被打印出。
「總結」:
- 如果數組為空且沒有提供 initialValue,會拋出TypeError 。
- 如果沒有提供 initialValue,reduce 會從索引1的地方開始執行 callback 方法,跳過第一個索引。如果提供 initialValue ,從索引0開始。
- acc為傳入函數的返回值,如果是 console.log,則返回默認值 undefined
filter()
定義:創建一個新數組, 其包含通過所提供函數實現的測試的所有元素。
先來介紹語法:
let?newArray?=?array.filter(function(currentValue,?index,?arr),?thisArg)callback:為數組中每個元素執行的函數,該函數接收一至三個參數 currentValue 數組中正在處理的當前元素 index (可選) ?數組中正在處理的當前元素的索引 arr (可選) ? ?filter() 方法正在操作的數組 thisArg(可選參數),當執行回調函數callback,用作this值
簡單例子:
let?arr?=?[1,?2,?3,?4,?5];let?newArr?=?arr.filter(function?(cur,?index)?{
??console.log(cur,?index);
??return?cur?%?2?==?0;
})
//?1?0
//?2?1
//?3?2
//?4?3
//?5?4
console.log(newArr);?//?[?2,?4?]
關于 thisArg 相關可以參考上文 array.forEach() 方法 部分。
簡單來說,就是返回滿足條件的結果。
every()
定義:測試一個數組內的所有元素是否「都能通過」某個指定函數的測試,它返回的是一個 Boolean 類型的值。
先來介紹語法:
array.every(function(currentValue,?index,?arr),?thisArg)callback:為數組中每個元素執行的函數,該函數接收一至三個參數 currentValue 數組中正在處理的當前元素 index (可選) ?數組中正在處理的當前元素的索引 arr (可選) ?every() 方法正在操作的數組 thisArg 可選參數,當執行回調函數callback,用作this值
let?res1?=?[1,?2,?3,?4,?5].every(function?(cur)?{??return?cur?>?10;
})
console.log(res1);?//?false
let?res2?=?[1,?2,?3,?4,?5].every(function?(cur)?{
??return?cur?>=?1;
})
console.log(res2);?//?true
關于 thisArg 相關可以參考上文 array.forEach() 方法 部分。
簡單來說,就是返回是否「都能滿足」特定條件的結果,用布爾值返回。
some()
定義:測試數組中是不是「至少有1個元素通過」了被提供的函數測試,它返回的是一個 Boolean 類型的值
先來介紹語法:
array.some(function(currentValue,?index,?arr),?thisArg)callback:為數組中每個元素執行的函數,該函數接收一至三個參數 currentValue 數組中正在處理的當前元素 index (可選) ?數組中正在處理的當前元素的索引 arr (可選) ? ?some() 方法正在操作的數組 thisArg ? ? (可選參數),當執行回調函數callback,用作this值
let?res1?=?[1,?2,?3,?4,?5].some(function?(cur)?{??return?cur?>?10;
})
console.log(res1);?//?false
let?res2?=?[1,?2,?3,?4,?5].some(function?(cur)?{
??return?cur?===?1;
})
console.log(res2);?//?true
關于 thisArg 相關可以參考上文 array.forEach() 方法 部分。
簡單來說,就是返回是否「至少有1個滿足」特定條件的結果,用布爾值返回。
find 和 findIndex
該方法在ECMAScript 6規范中被加入,可能不存在于某些實現中。
定義:
find: ?返回數組中滿足提供的測試函數的第一個元素的值。否則返回 ?undefined。
findIndex:數組中通過提供測試函數的第一個元素的索引。否則,返回 -1。
先來介紹語法:
let?ele?=?array.find(function(elemnet,?index,?arr),?thisArg)let?eleIndex?=?array.findIndex(function(elemnet,?index,?arr),?thisArg)callback:為數組中每個元素執行的函數,該函數接收一至三個參數 elemnet 數組中正在處理的當前元素 index (可選) ?數組中正在處理的當前元素的索引 arr (可選) ? ? find方法正在操作的數組 thisArg ? ? ?可選參數,當執行回調函數callback,用作this值
let?res1?=?[1,?2,?3,?4,?5].find(function?(cur)?{??return?cur?>?2;
})
console.log(res1);?//?3
let?res2?=?[1,?2,?3,?4,?5].findIndex(function?(cur)?{
??return?cur?>?2;
})
console.log(res2);?//?2
keys 與 values 與 entries
定義:
- keys() 方法返回一個包含數組中每個索引鍵的 「Array Iterator」 對象。
- values() 方法返回一個新的 Array Iterator 對象,該對象包含數組每個「索引的值」
- entries() 方法返回一個新的 Array Iterator 對象,該對象包含數組中每個「索引的鍵/值對」。
arr.values()
arr.entries()
簡單例子:
let?arr?=?['Chocolate',?'zhlll',?'lionkk'];let?itKeys?=?arr.keys();
let?itVals?=?arr.values();
let?itEntries?=?arr.entries();
for?(let?it?of?itKeys)?{
??console.log(it);
}
//?0
//?1
//?2
for?(let?it?of?itVals)?{
??console.log(it);
}
//?Chocolate
//?zhlll
//?lionkk
for?(let?it?of?itEntries)?{
??console.log(it);
}
//?[?0,?'Chocolate'?]
//?[?1,?'zhlll'?]
//?[?2,?'lionkk'?]
好了,到此關于數組的遍歷方式基本上介紹完畢了,也許還有其它方法,但是萬變不離其宗,接下來我們將探究 「改變原數組」 的方法。
改變原始數組方法
看過我之前關于 Vue 數據劫持源碼分析那篇博客文章小伙伴應該知道,里面就有提到了用「裝飾者模式」解決無法處理數組問題。其中就有提到對于改變原始數組的方法,這些需要繼續遞歸觀察。那么,接下來,我們就來分別探討一下它們的使用:
sort()
至于為什么我會排第一個,對,面試遇到過,當時我說對某手面試官說默認按照從小到大進行排序,通過學習后,我發現不是的...
先來介紹語法:
arr.sort([compareFunction])compareFunction 可選,用來指定按某種順序進行排列的函數。如果省略,元素按照轉換為的字符串的各個字符的Unicode位點進行排序。否則,如果指明了compareFunction:如果 compareFunction(a, b) 小于 0 ,那么 a 會被排列到 b 之前;如果 compareFunction(a, b) 等于 0 , a 和 b 的相對位置不變。如果 compareFunction(a, b) 大于 0 , b 會被排列到 a 之前。
簡單例子:
let?arr?=?[1,?10,?2,?5,?8,?3];arr.sort();?//?默認
console.log(arr);?//?[?1,?10,?2,?3,?5,?8?]
arr.sort((a,?b)?=>?a?-?b);?//?從小到大排序
console.log(arr);?//?[?1,?2,?3,?5,?8,?10?]
arr.sort((a,?b)?=>?b?-?a);?//?從大到小排序
console.log(arr);?//?[?10,?8,?5,?3,?2,?1?]
push()
類似棧、隊列的一些操作
「注意」,push() 成功之后會返回數組的長度。
let?arr?=?[1,2];let?res?=?arr.push(100);
console.log(arr);?//?[?1,?2,?100?]
console.log(res);?//?3
pop()
類似棧、隊列的一些操作
let?arr?=?[1,?2,?100];let?res?=?arr.pop();
console.log(arr);?//?[?1,?2?]
console.log(res);?//?100
shift()
類似棧、隊列的一些操作
let?arr?=?[1,?2,?100];let?res?=?arr.shift();
console.log(arr);?//?[?2,?100?]
console.log(res);?//?1
unshift()
定義:將一個或多個元素添加到 「數組的開頭」,并 (該方法修改原有數組)
「注意」:該方法會返回該數組的新長度
let?arr?=?[1,?2,?100];let?res?=?arr.unshift(4,?5,?6);
console.log(arr);?//?[?4,?5,?6,?1,?2,?100?]
console.log(res);?//?6
reverse()
定義:將數組中元素的位置顛倒,并返回該數組。
let?arr?=?[1,?2,?3];arr.reverse();
console.log(arr);//?[?3,?2,?1?]
splice()
這個我放最后一個也是有原因的,它比其它幾個要更復雜一點,剛開始我也是花了老長時間才理解,而且原本一直與 split() 這些分不清楚。
定義:
通過「刪除或替換」現有元素或者原地添加新的元素來修改數組,并以數組形式返回被修改的內容。
array.splice(start,deleteCount,item1,.....,itemX)zstart: 指定修改的開始位置(從0計數) 1. 如果超出了數組的長度,則從數組末尾開始添加內容 2. 如果是負值,則表示從數組末位開始的第幾位(從-1計數,這意味著-n是倒數第n個元素,并且等價于array.length-n) 3. 如果負數的絕對值大于數組的長度,則表示開始位置為第0位
deleteCount(可選) : 整數,表示要移除的數組元素個數 1. 如果 deleteCount 大于 start 之后的元素的總數,則從 start 后面的元素都將被 刪除(含第 start 位) 2. 如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是 ? 說,如果它大于或者等于start之后的所有元素的數量),那么start之后數組的所有元素都會被刪除。3. 如果 deleteCount 是 0 或者負數,則不移除元素。這種情況下,至少應添加一個新 ? 元素。
item1, item2, ...(可選) 要添加進數組的元素,從start 位置開始。如果不指定,則 splice() 將只刪除數組元素。
從第2位開始插入“Chocolate”
let?arr?=?['one',?'two',?'three'];arr.splice(2,?0,?'Chocolate');
console.log(arr);//?[?'one',?'two',?'Chocolate',?'three'?]
從第 2 位開始刪除 1 個元素,然后插入“Chocolate”
let?arr?=?['one',?'two',?'three'];arr.splice(2,?1,?'Chocolate');
console.log(arr);//?[?'one',?'two',?'Chocolate'?]
主流的還是這7個方法,對于改變原數組還有 fill() 和 copyWithin() 方法,小伙伴們可以繼續研究~
數組的映射
Array.map()方法
上文已經介紹
Array.from()方法
定義:通過在每個數組項上使用 callback 調用結果來創建一個新數組。
先來介紹語法:
?Array.from(Array,callback(currentValue,?index,?arr))簡單例子:
let?arr?=?[1,?2,?3];let?newArr?=?Array.from(arr,?function?(cur)?{
??return?cur?+?10;
})
console.log(newArr);//?[?11,?12,?13?]
數組的連接
Array.concat() 方法
array.concat(array1[, array2, ...]) 將一個或多個數組連接到原始數組。如下所示,連接兩個數組:
let?arrA?=?[1,?2,?3];let?arrB?=?[4,?5,?6];
let?ans?=?arrA.concat(arrB);
console.log(ans);//?[?1,?2,?3,?4,?5,?6?]
展開操作符
let?arrA?=?[1,?2,?3];let?arrB?=?[4,?5,?6];
let?ans?=?[...arrA,?...arrB];
console.log(ans);//?[?1,?2,?3,?4,?5,?6?]
獲取數組的片段
Array.slice() 方法
定義:返回一個新的數組對象,這一對象是一個由 begin 和 end 決定的原數組的「淺拷貝」(包括 begin,不包括 end)——原始數組不會被改變。
先介紹語法:
arr.slice([begin[,?end]])begin (可選)
end ? (可選)
let?res?=?fruits.slice(1,?3);
let?res1?=?fruits.slice(1);
let?res2?=?fruits.slice(-1);
let?res3?=?fruits.slice(0,?-1);
console.log(res);?//?[?'Orange',?'Lemon'?]
console.log(res1);//?[?'Orange',?'Lemon',?'Apple',?'Mango'?]
console.log(res2);//?[?'Mango'?]
console.log(res3);//?[?'Banana',?'Orange',?'Lemon',?'Apple'?]
轉換數組
join()
定義:
將一個數組(或一個類數組對象)的所有元素連接成一個字符串并返回這個字符串。如果數組只有一個項目,那么將返回該項目而不使用分隔符。
語法:
arr.join(separator)簡單例子:
let?arr?=?['one',?'two',?'three'];let?res?=?arr.join('^');
let?res1?=?arr.join('&');
console.log(res);?//?one^two^three
console.log(res1);?//?one&two&three
split()
定義:
使用指定的分隔符字符串將一個 String 對象分割成子字符串數組,以一個指定的分割字串來決定每個拆分的位置。
語法:
str.split([separator[,?limit]])const?str?=?'The?best?Chocolate';
const?words?=?str.split('?');
console.log(words);?//?[?'The',?'best',?'Chocolate'?]
console.log(words[2]);?//?Chocolate
toString()
定義:
返回一個字符串,表示指定的數組及其元素。
當一個數組被作為文本值或者進行字符串連接操作時,將會自動調用其 toString 方法。
語法:
arr.toString()let?arr?=?['one',?'two',?'three'];
console.log(arr.toString());?//?one,two,three
數組的扁平化
flat()
定義:
按照一個可指定的深度遞歸遍歷數組,并將所有元素與遍歷到的子數組中的元素合并為一個新數組返回。
語法:
var?newArray?=?arr.flat([depth])參數 depth 可選 指定要提取嵌套數組的結構深度,默認值為 1。返回值 一個包含將數組與子數組中所有元素的新數組。
const?arr1?=?[0,?1,?2,?[3,?4]];console.log(arr1.flat());?//?[?0,?1,?2,?3,?4?]
const?arr2?=?[0,?1,?2,?[[[3,?4]]]];
console.log(arr2.flat(2));?//?[?0,?1,?2,?[?3,?4?]?]
備忘錄
女朋友表示說:感動了!
本文參考
感謝大佬~
- 「數組方法」從詳細操作js數組到淺析v8中array.js
- MDN_Array
- 通過事例重溫一下 JS 中 常見的15 種數組操作(備忘清單)
- JS數組奇巧淫技
- JS之數組的幾個不low操作
最后
文章產出不易,還望各位小伙伴們支持一波!
往期精選:
小獅子前端の筆記倉庫
leetcode-javascript:LeetCode 力扣的 JavaScript 解題倉庫,前端刷題路線(思維導圖)
小伙伴們可以在Issues中提交自己的解題代碼,? 歡迎Contributing,可打卡刷題,Give a ?? if this project helped you!
訪問超逸の博客,方便小伙伴閱讀玩耍~
學如逆水行舟,不進則退
最后,給大家推薦非常好的課程,最近已經學完了,學完對于你理解瀏覽器工作原理與實踐將有很大幫助,謝謝大家支持~
覺得不錯,點個【在看】支持一下,或者分享給女友們~
總結
以上是生活随笔為你收集整理的js map 排序_数组方法写给女友的一系列 JS 数组操作(建议收藏 | 内附思维导图)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: u盘复制不进去东西_确认过眼神,是电脑小
- 下一篇: python布尔系列_python –