本文首發於 劉星的我的網站 liuxing.io
在 JavaScript 中,除了 Object 以外,數組(Array)應該是最經常使用的類型了。數組是一組有序的數據,使用方括號表示[1, 2, 3]
,可經過索引來訪問每一個元素(索引從 0 開始)。 JavaScript 中的數組的長度和元素類型都是非固定的。javascript
首先咱們來看看數組的幾種建立方式:字面量方式、 Array 構造函數、 擴展運算符(...
)、ES6 新增的用於建立數組的靜態方法from()
和of()
java
數組字面量(array literal)應該是 JavaScript 中最爲經常使用的建立方式了,在初始化數組的時候至關方便。數組字面量是在中括號中包含以逗號分隔的元素列表。es6
const users = ['LiuXing', 'liuixng.io']; console.log(users.length); // 2
上面這個例子中建立了一個包含兩個字符串的數組。數組
還可使用 Array 構造函數來建立數組。能夠給Array()
構造函數傳入一個數字,建立一個長度爲傳入值得數組;也能夠給 Array 構造函數傳入要保存的元素,建立包含傳入值的數組。數據結構
// 傳入要保存的元素 const users = Array('LiuXing', 'liuxing.io'); ['LiuXing', 'liuxing.io'] console.log(users.length); // 2 const arr1 = new Array(); [] // 傳入數字 直接建立一個長度爲3的數組 const arr2 = Array(3); [,,] console.log(users.length); // 3
在使用 Array 構造函數時,加不加 new 操做符,結果都同樣。函數
可使用擴展運算符 ...
在一個數組字面量裏包含另外一個數組的元素。擴展運算符能夠很方便的建立一個淺拷貝的數組。擴展運算符還能夠用於任何可迭代的對象。測試
const original = [1, 2, 3]; const copy = [...original] copy[0] = 0 // 修改copy不會法改變原數組 original[0] // 1
ES6 Array 新增了兩個用於建立數組的靜態方法: from()
和 of()
。from()
用於將類數組轉換爲數組,而 of()
用於將一組參數轉換爲數組。網站
從類數組對象或者可迭代對象中建立一個新的數組實例。ui
Array.form()
能夠接收 3 個參數:this
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(7); // [7] Array.of(1, 2, 3); // [1, 2, 3]
本質上,數組屬於一種特殊的對象。typeof
運算符會返回數組的類型是object
。有一個經典問題是判斷一個對象是否是數組,一般能夠經過 instanceof
、 constructor
已經 Object.prototype.toString
來判斷,可是前兩這個可能不許確,後者較麻煩。爲解決這個小問題,JavaScript 提供了 Array.isArray()
方法,它返回一個布爾值,表示參數是否爲數組。它能夠彌補 typeof
運算符的不足。
Array.isArray([1, 2, 3]); // true Array.isArray({foo: 123}); // false Array.isArray("foobar"); // false Array.isArray(undefined); // false
可是在不支持該方法的環境中咱們能夠提供以下 Polyfill,也就是使用Object.prototype.toString
來判斷
if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }
數組的方法有不少,本文會將這些方法分爲操做方法、排序方法、棧與隊列方法、迭代方法、搜索方法及數組的轉換方法一一講解。在數組的操做方法中只有concat()
與slice()
不會改變原數組,其餘方法均會改變原數組。全部的排序方法都會改變原數組。全部棧與隊列方法也會改變原數組。
對於數組中的元素,咱們有不少操做方法,如:concat()
用於鏈接兩個數組。slice()
用於切片,splice()
在數組中間刪除或插入元素...
concat
方法用於多個數組的合併。它將新數組的元素,添加到原數組元素的後部,而後返回一個新的結果數組,原數組不變。
['liu', 'xing'].concat(['love', 'dev']) // ["liu", "xing", "love", 'dev']
若是傳入一個或多個數組,則 concat()
會把這些數組的每一項都添加到結果數組。若是參數不是數組,則直接把它們添加到結果數組末尾
[1, 2, 3].concat(4, 5, 6) // [1, 2, 3, 4, 5, 6]
同時,concat
方法還能夠很方便的建立一個當前數組的一個淺拷貝。
slice()
方法用於切片,即截取數組的中的部分元素,而後返回一個新數組,原數組不變。
slice()
方法能夠接收一個或兩個參數:返回元素的開始索引和結束索引。slice()
返回的結果包括開始索引,不包括結束索引。
arr.slice(start, end);
若是有兩個參數,則 slice()
返回從開始索引到結束索引對應的全部元素,其中不包含結束索引對應的元素。
arr.slice(start, end);
若是隻有一個參數,則 slice()會返回該索引到數組末尾的全部元素。
arr.slice(start, end);
若是不給slice()
傳遞任何參數,它就會從頭至尾截取全部元素,等於返回了一個原數組的拷貝。
arr.slice(start, end);
若是slice()
方法的參數是負數,則表示倒數計算的位置
arr.slice(start, end);
或許最強大的數組方法就屬 splice()
了,他是修改數組的「萬能方法」,它能夠從指定的索引開始刪除若干元素,而後再從該位置添加若干元素。返回值是被刪除的元素,該方法會改變原數組。
arr.splice(start, count, addElement1, addElement2, ...);
splice
的第一個參數是指定修改的開始位置(從 0 計數),第二個參數是被刪除的元素個數。若是後面還有更多的參數,則表示這些就是要被插入數組的新元素。
主要有如下三種使用方式:
splice()
傳 2 個參數: 要刪除的第一個元素的位置和要刪除的元素數量。能夠從splice(0, 2)
會刪除前兩個元素。splice()
傳 3 個參數: 開始插入位置索引、0(刪除 0 個元素)和要插入的元素,可splice()
在刪除元素的同時能夠在指定位置插入新元素,這樣咱們能夠很方便實現元素的替換。如splice(2, 1, "liuxing")
會在位置 2 刪除一個元素,而後從該位置開始向數組中插入"liuxing"。copyWithin()
方法能夠淺複製數組的一部分到同一數組中的另外一個位置,並返回它,不會改變原數組的長度。
[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
fill()
方法能夠用一個固定值填充一個數組中從起始索引到終止索引內的所有元素。不包括終止索引。
['a', 'b', 'c'].fill(7) // [7, 7, 7] new Array(3).fill(7) // [7, 7, 7]
sort
方法可對數組成員進行排序,排序後原數組將被改變。默認排序順序是在將元素轉換(調用 String()
轉型函數)爲字符串,而後比較它們的 UTF-16 代碼單元值序列時構建的。如:
let values = [0, 3, 1, 2, 10]; values.sort(); console.log(values); // [0, 1, 10, 2, 3]
從上例能夠看到,默認的排序方法,對數字的排序是有問題的,爲此,sort()方法能夠接收一個比較函數做爲第二個參數,用於判斷哪一個值應該排在前面。比較函數能夠接收兩個參數,表示進行比較的兩個數組成員。
格式以下
function compare(a, b) { if (a < b ) { // 按某種排序標準進行比較, a 小於 b return -1; } if (a > b ) { return 1; } // a must be equal to b return 0; }
對於前面的實例數組的排序能夠寫成這樣
let values = [0, 3, 1, 2, 10]; values.sort((a, b) => a - b); console.log(values); // [0, 1, 2, 3, 10]
顧名思義,reverse()
方法就是將數組元素反向排列。該方法將改變原數組。
let values = [1, 2, 3, 4, 5]; values.reverse(); console.log(values); // 5,4,3,2,1
JavaScript 的數組以及原生方法能夠很好的模擬另外兩種經常使用數據結構:棧與隊列
棧是一種後進先出(LIFO,Last-In-First-Out)的結構,也就是最近添加的項先被刪除。數據項的插入(稱爲推入,push)和刪除(稱爲彈出,pop)只在棧的一個地方發生,即棧頂。JavaScript 數組提供了 push()和 pop()方法,以實現相似棧的行爲。
push()
方法用於向數組末尾添加元素(任意數量的元素),返回數組的最新長度,該方法會改變原數組。
let arr = []; arr.push(1) // 1 arr.push('liuxing') // 2 arr // [1, 'liuxing', true, {}]
pop()
方法用於刪除數組的最後一個元素,並返回該元素。該方法會改變原數組。
let arr = ['a', 'b', 'c']; arr.pop() // 'c' arr // ['a', 'b']
隊列以先進先出(FIFO,First-In-First-Out)形式限制訪問。隊列在列表末尾添加數據,但從列表開頭獲取數據。由於有了在數據末尾添加數據的 push()方法,因此要模擬隊列就差一個從數組開頭取得數據的方法了。這個數組方法叫 shift(),它會刪除數組的第一項並返回它,而後數組長度減 1。使用 shift()和 push(),能夠把數組當成隊列來使用
shift()
方法用於刪除數組的第一個元素,並返回該元素。該方法會改變原數組。
let arr = ['a', 'b', 'c']; arr.shift() // 'a' arr // ['b', 'c']
unshift()
方法用於在數組的第一個位置添加元素,並返回添加新元素後的數組長度。該方法會改變原數組。
let arr = ['a', 'b', 'c']; arr.unshift('liuixng'); // 4 arr // ['liuxing', 'a', 'b', 'c']
ES6 數組提供三個新的用於檢索數組內容的方法: entries()
,keys()
和values()
。它們都返回一個迭代器對象。keys()
返回數組索引的迭代器,values()
返回數組元素的迭代器,而 entries()
返回鍵/值對的迭代器。能夠用for...of
循環進行遍歷。
返回一個包含全部數組元素的索引的迭代器對象。
for (let index of ['a', 'b'].keys()) { console.log(index); } // 0 // 1
返回一個包含全部數組元素值得迭代器對象。
for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b'
返回一個包含全部數組元素的鍵值對迭代器對象。
for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" // 1 "b"
forEach
方法迭代數組的每個元素,並對每一個元素都調用一次咱們指定的回調函數。它不返回值,只用來操做數據。forEach()
方法至關於使用 for
循環遍歷數組。
let numbers = [1, 2, 3, 4, 5]; numbers.forEach((item, index, array) => { // 執行某些操做 console.log(item) });
map()
會將數組的每一個元素都按順序傳入回調函數,而後返回由每次函數調用的結果組成的新數組。 注意:回調 函數只會在有值的索引上被調用。
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()
用於打平數組。即從多維數組轉化爲一位數組。該方法接收一個參數(默認爲 1),用於指定的深度遍歷,而後將全部元素與遍歷到的子數組中的元素合併爲一個新數組返回。
[1, 2, [3, 4]].flat() // [1, 2, 3, 4]
若是想要打平不管多少層的數組,能夠傳入Infinity
做爲參數
[1, [2, [3]]].flat(Infinity) // [1, 2, 3]
flatMap()
與 map()
方法類似。只不過返回的數組會自動被打平。調用flatMap()
等同於調用map()
,可是flatMap()
效率更高。
[2, 3, 4].flatMap((x) => [x, x * 2]) // [2, 4, 3, 6, 4, 8]
filter()
方法用於過濾數組元素。它會對數組每一項都運行傳入的函數,返回結果爲true
的元素將組成一個新數組返回。該方法不會改變原數組。
let numbers = [1, 2, 3, 4, 5]; let filterResult = numbers.filter((item, index, array) => item > 2); console.log(filterResult); // [3, 4, 5]
some()
與 every()
十分類似,都用於判斷數組中的元素是否符合某種條件(斷言函數)。
every()
來講,傳入的函數必須對每一項都返回 true
,它纔會返回 true
;some()
來講,只要有一項讓傳入的函數返回 true
,它就會返回 true
。若是數組中至少有一個元素知足測試函數,則返回 true
,不然返回 false
。
let numbers = [1, 2, 3, 4, 5]; let everyResult = numbers.every((item, index, array) => item > 2); console.log(everyResult); // false
若是數組中的每一個元素都知足測試函數,則返回 true
,不然返回 false。
let numbers = [1, 2, 3, 4, 5]; let someResult = numbers.some((item, index, array) => item > 2); console.log(everyResult); // true
reduce()
和 reduceRight()
這兩個方法都會迭代數組的全部項,並在此基礎上累計構建一個最終返回值。reduce()
方法從數組第一項開始遍歷到最後一項。而reduceRight()
從最後一項開始遍歷至第一項。
從左到右爲每一個數組元素執行一次回調函數,並把上次回調函數的返回值放在一個暫存器中傳給下次回調函數,並返回最後一次回調函數的返回值。
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
從右到左爲每一個數組元素執行一次回調函數,並把上次回調函數的返回值放在一個暫存器中傳給下次回調函數,並返回最後一次回調函數的返回值。
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
JavaScript 提供兩類搜索數組的方法:按嚴格相等搜索和按斷言函數搜索。
indexOf()
、lastIndexOf()
和 includes()
是按嚴格相等的搜索方法,它們都這些方法都接收兩個參數: 要查找的元素和一個可選的起始搜索位置。find()
和 findIndex()
方法使用了斷言函數。它們接收 3 個參數: 元素、索引和數組自己indexOf
方法返回給定元素在數組中第一次出現的位置,若是沒有出現則返回-1
,它還能夠接受第二個參數,表示搜索的開始位置
let arr = Array.from('liuxing'); arr.indexOf('i') // 1 arr.indexOf('i', 2) // 4
lastIndexOf
方法返回給定元素在數組中最後一次出現的位置(從後往前找),若是沒有出現則返回-1
。
let arr = Array.from('liuxing'); arr.lastIndexOf('i') // 4 arr.lastIndexOf('i',3) // 1
includes()
方法用來判斷一個數組是否包含一個指定的值,返回布爾值。若是包含則返回 true,不然返回 false。
let arr = Array.from('liuxing'); arr.includes('i') // true arr.includes('io') // false
find()
方法返回數組中知足斷言函數的第一個元素的值。不然返回 undefined。
const people = [ { name: "LiuXing", age: 99 }, { name: "XingLiu", age: 9 } ]; people.find(element => element.name === 'LiuXing') // {name: "LiuXing", age: 99}
findIndex()
方法返回數組中知足斷言函數的第一個元素的位置。不然返回 -1。
const people = [ { name: "LiuXing", age: 99 }, { name: "XingLiu", age: 9 } ]; people.findIndex(element => element.name === 'LiuXing') // 0
全部對象都有 toLocaleString()
、toString()
和 valueOf()
方法。其中,數組的valueOf()
返回的仍是數組自己。而 toString()
返回由數組中每一個值的等效字符串拼接而成的一個逗號分隔的字符串。也就是說,對數組的每一個值都會調用其 toString()
方法,以獲得最終的字符串。
valueOf
方法是一個全部對象都擁有的方法,表示對該對象求值。數組的valueOf
方法返回數組自己。
let arr = [1, 2, 3]; arr.valueOf() // [1, 2, 3]
toString
方法也是對象的通用方法,toLocaleString()
與toString()
的區別在於toLocaleString()
與執行環境的地區對應,如日期對象。數組的toString
及toLocaleString()
方法返回數組的字符串形式。
let arr = [10000, 20000, 3000]; arr.toString() // 10000,20000,3000 arr.toLocaleString() // "10,000,20,000,3,000"
join()
方法接收一個做爲字符串分隔符的參數,將全部數組成員鏈接爲一個字符串返回。若是不提供參數,默認用逗號分隔。
let a = [1, 2, 3, 4, 5]; a.join(' ') // '1 2 3 4 5' a.join() // "1,2,3,4,5"
本文從數組的建立講到數組的檢測,最後講了數組的各類方法,如數組的遍歷方法、搜索方法等。這是一篇偏文檔式的文章,須要常常複習。
本文完
歡迎能夠關注個人公衆號,一塊兒玩耍。有技術乾貨也有扯淡亂談
左手代碼右手磚,拋磚引玉
文檔信息
版權聲明:署名-非商業性使用-禁止演繹 4.0 國際(CC BY-NC-ND 4.0)
原文連接:https://www.liuxing.io/blog/j...發表日期:2021年04月17日