Javascript 數(shù)組及其方法詳解
點擊上方藍字關注我們?

簡介
在 JavaScript 中,除了 Object 之外,數(shù)組(Array)應該是最常用的類型了。數(shù)組是一組有序的數(shù)據(jù),使用方括號表示[1, 2, 3],可通過索引來訪問每個元素(索引從 0 開始)。JavaScript 中的數(shù)組的長度和元素類型都是非固定的。
數(shù)組的創(chuàng)建
首先我們來看看數(shù)組的幾種創(chuàng)建方式:字面量方式、 Array 構造函數(shù)、 擴展運算符(...)、ES6 新增的用于創(chuàng)建數(shù)組的靜態(tài)方法from()和of()
###數(shù)組字面量
數(shù)組字面量(array literal)應該是 JavaScript 中最為常用的創(chuàng)建方式了,在初始化數(shù)組的時候相當方便。數(shù)組字面量是在中括號中包含以逗號分隔的元素列表。
const users = ['LiuXing', 'liuixng.io'];
console.log(users.length); // 2
上面這個例子中創(chuàng)建了一個包含兩個字符串的數(shù)組。
構造函數(shù)
還可以使用 Array 構造函數(shù)來創(chuàng)建數(shù)組。可以給Array()構造函數(shù)傳入一個數(shù)字,創(chuàng)建一個長度為傳入值的數(shù)組;也可以給 Array 構造函數(shù)傳入要保存的元素,創(chuàng)建包含傳入值的數(shù)組。
// 傳入要保存的元素
const users = Array('LiuXing', 'liuxing.io'); ['LiuXing', 'liuxing.io']
console.log(users.length); // 2
const arr1 = new Array(); []
// 傳入數(shù)字 直接創(chuàng)建一個長度為3的數(shù)組
const arr2 = Array(3); [,,]
console.log(users.length); // 3
在使用 Array 構造函數(shù)時,加不加 new 操作符,結果都一樣。
擴展運算符
可以使用擴展運算符 ... 在一個數(shù)組字面量里包含另一個數(shù)組的元素。擴展運算符可以很方便的創(chuàng)建一個淺拷貝的數(shù)組。擴展運算符還可以用于任何可迭代的對象。
const original = [1, 2, 3];
const copy = [...original]
copy[0] = 0 // 修改copy不會改變原數(shù)組
original[0] // 1
Array 靜態(tài)方法
ES6 Array 新增了兩個用于創(chuàng)建數(shù)組的靜態(tài)方法: from() 和 of()。from()用于將類數(shù)組轉換為數(shù)組,而 of()用于將一組參數(shù)轉換為數(shù)組。
Array.form()
從類數(shù)組對象或者可迭代對象中創(chuàng)建一個新的數(shù)組實例。
Array.form()可以接收 3 個參數(shù):
第一個必須參數(shù)為想要轉換成數(shù)組的偽數(shù)組對象或可迭代對象:如 Map 和 Set、Arguments 對象 第二個是可選的映射函數(shù)參數(shù),可以直接增強新數(shù)組的值,類似數(shù)組的 map 方法 第三個可選參數(shù),用于指定映射函數(shù)中 this 的值,但這個重寫的 this 值在箭頭函數(shù)中不適用
console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]
console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]
const a1 = [1, 2, 3, 4];
const a2 = Array.from(a1, function(x) {return x**this.exponent}, {exponent: 2});
console.log(a2); // [1, 4, 9, 16]
Array.of()
根據(jù)一組參數(shù)來創(chuàng)建新的數(shù)組實例,支持任意的參數(shù)數(shù)量和類型。將按順序成為返回數(shù)組中的元素。
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
數(shù)組的檢測
本質上,數(shù)組屬于一種特殊的對象。typeof運算符會返回數(shù)組的類型是object。有一個經典問題是判斷一個對象是不是數(shù)組,通常可以通過 instanceof、 constructor 已經 Object.prototype.toString來判斷,但是前兩這個可能不準確,后者較麻煩。為解決這個小問題,JavaScript 提供了 Array.isArray() 方法,它返回一個布爾值,表示參數(shù)是否為數(shù)組。它可以彌補 typeof 運算符的不足。
Array.isArray([1, 2, 3]);
// true
Array.isArray({foo: 123});
// false
Array.isArray("foobar");
// false
Array.isArray(undefined);
// false
但是在不支持該方法的環(huán)境中我們可以提供如下 Polyfill,也就是使用Object.prototype.toString來判斷
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
數(shù)組方法
數(shù)組的方法有很多,本文會將這些方法分為操作方法、排序方法、棧與隊列方法、迭代方法、搜索方法及數(shù)組的轉換方法一一講解。在數(shù)組的操作方法中只有concat()與slice() 不會改變原數(shù)組,其他方法均會改變原數(shù)組。所有的排序方法都會改變原數(shù)組。所有棧與隊列方法也會改變原數(shù)組。
數(shù)組的操作方法
對于數(shù)組中的元素,我們有很多操作方法,如:concat() 用于連接兩個數(shù)組。slice() 用于切片,splice() 在數(shù)組中間刪除或插入元素...
contact()
concat 方法用于多個數(shù)組的合并。它將新數(shù)組的元素,添加到原數(shù)組元素的后部,然后返回一個新的結果數(shù)組,原數(shù)組不變。
['liu', 'xing'].concat(['love', 'dev'])
// ["liu", "xing", "love", 'dev']
如果傳入一個或多個數(shù)組,則 concat()會把這些數(shù)組的每一項都添加到結果數(shù)組。如果參數(shù)不是數(shù)組,則直接把它們添加到結果數(shù)組末尾
[1, 2, 3].concat(4, 5, 6)
// [1, 2, 3, 4, 5, 6]
同時,concat 方法還可以很方便的創(chuàng)建一個當前數(shù)組的一個淺拷貝。
slice()
slice() 方法用于切片,即截取數(shù)組的中的部分元素,然后返回一個新數(shù)組,原數(shù)組不變。
slice()方法可以接收一個或兩個參數(shù):返回元素的開始索引和結束索引。slice()返回的結果包括開始索引,不包括結束索引。
arr.slice(start, end);
如果有兩個參數(shù),則 slice() 返回從開始索引到結束索引對應的所有元素,其中不包含結束索引對應的元素。
arr.slice(start, end);
如果只有一個參數(shù),則 slice()會返回該索引到數(shù)組末尾的所有元素。
arr.slice(start, end);
如果不給slice()傳遞任何參數(shù),它就會從頭到尾截取所有元素,等于返回了一個原數(shù)組的拷貝。
arr.slice(start, end);
如果slice()方法的參數(shù)是負數(shù),則表示倒數(shù)計算的位置
arr.slice(start, end);
splice()
或許最強大的數(shù)組方法就屬 splice()了,他是修改數(shù)組的“萬能方法”,它可以從指定的索引開始刪除若干元素,然后再從該位置添加若干元素。返回值是被刪除的元素,該方法會改變原數(shù)組。
arr.splice(start, count, addElement1, addElement2, ...);
splice 的第一個參數(shù)是指定修改的開始位置(從 0 計數(shù)),第二個參數(shù)是被刪除的元素個數(shù)。如果后面還有更多的參數(shù),則表示這些就是要被插入數(shù)組的新元素。
主要有以下三種使用方式:
刪除。需要給
splice()傳 2 個參數(shù): 要刪除的第一個元素的位置和要刪除的元素數(shù)量。可以從 數(shù)組中刪除任意多個元素,比如splice(0, 2)會刪除前兩個元素。插入。需要給
splice()傳 3 個參數(shù): 開始插入位置索引、0(刪除 0 個元素)和要插入的元素,可 以在數(shù)組中指定的位置插入元素。第三個參數(shù)之后還可以傳第四個、第五個參數(shù),乃至任意多 個要插入的元素。替換。
splice()在刪除元素的同時可以在指定位置插入新元素,這樣我們可以很方便實現(xiàn)元素的替換。如splice(2, 1, "liuxing")會在位置 2 刪除一個元素,然后從該位置開始向數(shù)組中插入"liuxing"。
copyWithin()
copyWithin() 方法可以淺復制數(shù)組的一部分到同一數(shù)組中的另一個位置,并返回它,不會改變原數(shù)組的長度。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
fill()
fill() 方法可以用一個固定值填充一個數(shù)組中從起始索引到終止索引內的全部元素。不包括終止索引。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
排序方法
sort()
sort方法可對數(shù)組成員進行排序,排序后原數(shù)組將被改變。默認排序順序是在將元素轉換(調用 String() 轉型函數(shù))為字符串,然后比較它們的 UTF-16 代碼單元值序列時構建的。如:
let values = [0, 3, 1, 2, 10];
values.sort();
console.log(values); // [0, 1, 10, 2, 3]
從上例可以看到,默認的排序方法,對數(shù)字的排序是有問題的,為此,sort()方法可以接收一個比較函數(shù)作為第二個參數(shù),用于判斷哪個值應該排在前面。比較函數(shù)可以接收兩個參數(shù),表示進行比較的兩個數(shù)組成員。
如果第一個參數(shù)應該排在第二個參數(shù)前面,就返回負值; 如果兩個參數(shù)相等,就返回 0; 如果第一個參數(shù)應該排在第二個參數(shù)后面,就返回正值。
格式如下
function compare(a, b) {
if (a < b ) { // 按某種排序標準進行比較, a 小于 b
return -1;
}
if (a > b ) {
return 1;
}
// a must be equal to b
return 0;
}
對于前面的實例數(shù)組的排序可以寫成這樣
let values = [0, 3, 1, 2, 10];
values.sort((a, b) => a - b);
console.log(values); // [0, 1, 2, 3, 10]
reverse()
顧名思義,reverse() 方法就是將數(shù)組元素反向排列。該方法將改變原數(shù)組。
let values = [1, 2, 3, 4, 5];
values.reverse();
console.log(values); // 5,4,3,2,1
棧與隊列
JavaScript 的數(shù)組以及原生方法可以很好的模擬另外兩種常用數(shù)據(jù)結構:棧與隊列
棧是一種后進先出(LIFO,Last-In-First-Out)的結構,也就是最近添加的項先被刪除。數(shù)據(jù)項的插入(稱為推入,push)和刪除(稱為彈出,pop)只在棧的一個地方發(fā)生,即棧頂。JavaScript 數(shù)組提供了 push()和 pop()方法,以實現(xiàn)類似棧的行為。
push()
push()方法用于向數(shù)組末尾添加元素(任意數(shù)量的元素),返回數(shù)組的最新長度,該方法會改變原數(shù)組。
let arr = [];
arr.push(1) // 1
arr.push('liuxing') // 2
arr // [1, 'liuxing', true, {}]
pop()
pop() 方法用于刪除數(shù)組的最后一個元素,并返回該元素。該方法會改變原數(shù)組。
let arr = ['a', 'b', 'c'];
arr.pop() // 'c'
arr // ['a', 'b']
隊列以先進先出(FIFO,F(xiàn)irst-In-First-Out)形式限制訪問。隊列在列表末尾添加數(shù)據(jù),但從列表開頭獲取數(shù)據(jù)。因為有了在數(shù)據(jù)末尾添加數(shù)據(jù)的 push()方法,所以要模擬隊列就差一個從數(shù)組開頭取得數(shù)據(jù)的方法了。這個數(shù)組方法叫 shift(),它會刪除數(shù)組的第一項并返回它,然后數(shù)組長度減 1。使用 shift()和 push(),可以把數(shù)組當成隊列來使用
shift()
shift()方法用于刪除數(shù)組的第一個元素,并返回該元素。該方法會改變原數(shù)組。
let arr = ['a', 'b', 'c'];
arr.shift() // 'a'
arr // ['b', 'c']
unshift()
unshift()方法用于在數(shù)組的第一個位置添加元素,并返回添加新元素后的數(shù)組長度。該方法會改變原數(shù)組。
let arr = ['a', 'b', 'c'];
arr.unshift('liuixng'); // 4
arr // ['liuxing', 'a', 'b', 'c']
數(shù)組的迭代方法
ES6 數(shù)組提供三個新的用于檢索數(shù)組內容的方法: entries(),keys()和values() 。它們都返回一個迭代器對象。keys()返回數(shù)組索引的迭代器,values()返回數(shù)組元素的迭代器,而 entries()返回鍵/值對的迭代器。可以用for...of循環(huán)進行遍歷。
keys()
返回一個包含所有數(shù)組元素的索引的迭代器對象。
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
values()
返回一個包含所有數(shù)組元素值的迭代器對象。
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
entries()
返回一個包含所有數(shù)組元素的鍵值對迭代器對象。
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
forEach()
forEach 方法迭代數(shù)組的每一個元素,并對每個元素都調用一次我們指定的回調函數(shù)。它不返回值,只用來操作數(shù)據(jù)。forEach() 方法相當于使用 for 循環(huán)遍歷數(shù)組。
let numbers = [1, 2, 3, 4, 5];
numbers.forEach((item, index, array) => {
// 執(zhí)行某些操作
console.log(item)
});
map()
map()會將數(shù)組的每個元素都按順序傳入回調函數(shù),然后返回由每次函數(shù)調用的結果組成的新數(shù)組。注意:回調 函數(shù)只會在有值的索引上被調用。
let numbers = [1, 2, 3, 4, 5];
let mapResult = numbers.map((item, index, array) => item * 2);
console.log(mapResult); // [2,4,6,8,10]
flat()
flat() 用于打平數(shù)組。即從多維數(shù)組轉化為一位數(shù)組。該方法接收一個參數(shù)(默認為 1),用于指定的深度遍歷,然后將所有元素與遍歷到的子數(shù)組中的元素合并為一個新數(shù)組返回。
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
如果想要打平無論多少層的數(shù)組,可以傳入Infinity作為參數(shù)
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
flatMap()
flatMap() 與 map() 方法相似。只不過返回的數(shù)組會自動被打平。調用flatMap()等同于調用map(),但是flatMap()效率更高。
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
filter()
filter() 方法用于過濾數(shù)組元素。它會對數(shù)組每一項都運行傳入的函數(shù),返回結果為true的元素將組成一個新數(shù)組返回。該方法不會改變原數(shù)組。
let numbers = [1, 2, 3, 4, 5];
let filterResult = numbers.filter((item, index, array) => item > 2);
console.log(filterResult); // [3, 4, 5]
some() 與 every()十分相似,都用于判斷數(shù)組中的元素是否符合某種條件(斷言函數(shù))。
對 every()來說,傳入的函數(shù)必須對每一項都返回true,它才會返回true;對 some()來說,只要有一項讓傳入的函數(shù)返回true,它就會返回true。
some()
如果數(shù)組中至少有一個元素滿足測試函數(shù),則返回 true,否則返回 false。
let numbers = [1, 2, 3, 4, 5];
let everyResult = numbers.every((item, index, array) => item > 2);
console.log(everyResult); // false
every()
如果數(shù)組中的每個元素都滿足測試函數(shù),則返回 true,否則返回 false。
let numbers = [1, 2, 3, 4, 5];
let someResult = numbers.some((item, index, array) => item > 2);
console.log(everyResult); // true
reduce()和 reduceRight()這兩個方法都會迭代數(shù)組的所有項,并在此基礎上累計構建一個最終返回值。reduce()方法從數(shù)組第一項開始遍歷到最后一項。而reduceRight()從最后一項開始遍歷至第一項。
reduce()
從左到右為每個數(shù)組元素執(zhí)行一次回調函數(shù),并把上次回調函數(shù)的返回值放在一個暫存器中傳給下次回調函數(shù),并返回最后一次回調函數(shù)的返回值。
let values = [1, 2, 3, 4, 5];
let sum = values.reduce(function(prev, cur, index, array){
console.log(prev, cur)
return prev + cur;
});
// 1 2
// 3 3
// 6 4
// 10 5
console.log(sum) // 15
reduceRught()
從右到左為每個數(shù)組元素執(zhí)行一次回調函數(shù),并把上次回調函數(shù)的返回值放在一個暫存器中傳給下次回調函數(shù),并返回最后一次回調函數(shù)的返回值。
let values = [1, 2, 3, 4, 5];
let sum = values.reduceRight(function(prev, cur, index, array){
console.log(prev, cur)
return prev + cur;
});
// 5 4
// 9 3
// 12 2
// 14 1
console.log(sum) // 15
在數(shù)組中搜索
JavaScript 提供兩類搜索數(shù)組的方法:按嚴格相等搜索和按斷言函數(shù)搜索。
indexOf()、lastIndexOf()和includes()是按嚴格相等的搜索方法,它們都這些方法都接收兩個參數(shù): 要查找的元素和一個可選的起始搜索位置。find()和findIndex()方法使用了斷言函數(shù)。它們接收 3 個參數(shù): 元素、索引和數(shù)組本身
indexOf()
indexOf 方法返回給定元素在數(shù)組中第一次出現(xiàn)的位置,如果沒有出現(xiàn)則返回-1,它還可以接受第二個參數(shù),表示搜索的開始位置
let arr = Array.from('liuxing');
arr.indexOf('i') // 1
arr.indexOf('i', 2) // 4
lastIndexOf()
lastIndexOf 方法返回給定元素在數(shù)組中最后一次出現(xiàn)的位置(從后往前找),如果沒有出現(xiàn)則返回-1。
let arr = Array.from('liuxing');
arr.lastIndexOf('i') // 4
arr.lastIndexOf('i',3) // 1
includes()
includes() 方法用來判斷一個數(shù)組是否包含一個指定的值,返回布爾值。如果包含則返回 true,否則返回 false。
let arr = Array.from('liuxing');
arr.includes('i') // true
arr.includes('io') // false
find()
find() 方法返回數(shù)組中滿足斷言函數(shù)的第一個元素的值。否則返回 undefined。
const people = [
{
name: "LiuXing",
age: 99
},
{
name: "XingLiu",
age: 9
}
];
people.find(element => element.name === 'LiuXing') // {name: "LiuXing", age: 99}
findIndex()
findIndex() 方法返回數(shù)組中滿足斷言函數(shù)的第一個元素的位置。否則返回 -1。
const people = [
{
name: "LiuXing",
age: 99
},
{
name: "XingLiu",
age: 9
}
];
people.findIndex(element => element.name === 'LiuXing') // 0
數(shù)組的轉換方法
所有對象都有 toLocaleString()、toString()和 valueOf()方法。其中,數(shù)組的valueOf()返回的還是數(shù)組本身。而 toString()返回由數(shù)組中每個值的等效字符串拼接而成的一個逗號分隔的字符串。也就是說,對數(shù)組的每個值都會調用其 toString()方法,以得到最終的字符串。
valueOf()
valueOf 方法是一個所有對象都擁有的方法,表示對該對象求值。數(shù)組的valueOf方法返回數(shù)組本身。
let arr = [1, 2, 3];
arr.valueOf() // [1, 2, 3]
toString() 與 toLocaleString()
toString方法也是對象的通用方法,toLocaleString()與toString()的區(qū)別在于toLocaleString()與執(zhí)行環(huán)境的地區(qū)對應,如日期對象。數(shù)組的toString及toLocaleString()方法返回數(shù)組的字符串形式。
let arr = [10000, 20000, 3000];
arr.toString() // 10000,20000,3000
arr.toLocaleString() // "10,000,20,000,3,000"
join()
join() 方法接收一個作為字符串分隔符的參數(shù),將所有數(shù)組成員連接為一個字符串返回。如果不提供參數(shù),默認用逗號分隔。
let a = [1, 2, 3, 4, 5];
a.join(' ') // '1 2 3 4 5'
a.join() // "1,2,3,4,5"
總結
本文從數(shù)組的創(chuàng)建講到數(shù)組的檢測,最后講了數(shù)組的各種方法,如數(shù)組的遍歷方法、搜索方法等。這是一篇偏文檔式的文章,記得加入收藏經常復習。
參考鏈接
JavaScript Array - MDN ECMAScript 6 入門
本文完。
往期精彩回顧:
感謝閱讀,歡迎關注 ??
左手代碼右手磚,拋磚引玉
感謝點贊、關注、在看。
