Array
(數組)在JavaScript
中是最重要的數據結構之一,是類似列表的高階對象。Array
對象用於構造數組的全局對象。
數組中的每個元素對應一個索引(從0開始),同時每個數組有自己的length
屬性(等於該數組的元素個數(0~2^32-1)),每個數組都指向Array
構造函數的原型(Array.prototype
),即每個數組可以調用原型上定義的方法。
以下是數組常用方法的總結。
會改變數組自身的方法:
方法 | 描述 |
---|---|
Array.prototype.pop() | 刪除數組的最後一個元素,並返回這個元素(當數組爲空時返回undefined)。 |
Array.prototype.push() | 在數組的末尾增加一個或多個元素,並返回數組的新長度。 |
Array.prototype.shift() | 刪除數組的第一個元素,並返回這個元素。 |
Array.prototype.unshift() | 在數組的開頭增加一個或多個元素,並返回數組的新長度。 |
Array.prototype.reverse() | 顛倒數組中元素的排列順序,即原先的第一個變爲最後一個,原先的最後一個變爲第一個。 |
Array.prototype.sort() | 對數組元素進行排序,並返回當前數組。 |
Array.prototype.splice() | 在任意的位置給數組添加或刪除任意個元素。返回被刪除的元素組成的一個數組。 |
//會改變數組自身的方法
let arr = [1,2];
// Array.prototype.pop()
arr.pop(); // 2
console.log(arr); // [1]
// Array.prototype.push()
arr.push([1,2],[3,4]); // 3
console.log(arr); // [1,[1,2],[3,4]]
// Array.prototype.shift()
arr.shift(); // 1
console.log(arr); // [[1,2],[3,4]]
// Array.prototype.unshift()
arr.unshift([15]); // 3
console.log(arr); // [[15],[1,2],[3,4]]
// Array.prototype.reverse()
arr.reverse(); // [[3,4],[1,2],[15]]
// Array.prototype.sort()
// 默認會按照轉換爲的字符串的諸個字符的Unicode位點進行排序。
arr.sort(); // [[1,2],[15],[3,4]]
// 使用如下方法可對arr按數組每個元素第一個索引值進行升序排序
arr.sort((a, b) => a[0] - b[0]); // [[1,2],[3,4],[15]]
// Array.prototype.splice(start[, deleteCount[, item1[, item2[, ...]]]])
// start: 開始修改的索引號
// deleteCount: 要刪除的元素個數
// item...: 要插入的元素
arr.splice(1,2,3,4); // [[3,4],[15]]
console.log(arr); [[1,2],3,4];
不會改變數組自身的方法:
方法 | 描述 |
---|---|
Array.prototype.concat() | 返回一個由當前數組和其它若干個數組或者若干個非數組值組合而成的新數組。淺拷貝。 |
Array.prototype.join() | 連接所有數組元素組成一個字符串。 |
Array.prototype.slice() | 抽取當前數組中的一段元素組合成一個新數組。 |
Array.prototype.toString() | 返回一個由所有數組元素組合而成的字符串。遮蔽了原型鏈上的 Object.prototype.toString() 方法。 |
Array.prototype.toLocaleString() | 返回一個由所有數組元素組合而成的本地化後的字符串。遮蔽了原型鏈上的 Object.prototype.toLocaleString() 方法。 |
// 不會改變數組自身的方法
// Array.prototype.concat(value1[, value2[, ...[, valueN]]])
let num1 = [[1]];
let num2 = [2, [3]];
let nums = num1.concat(num2);
console.log(nums); // [[1], 2, [3]]
// 淺拷貝,改變原數組同時會改變新數組
num1[0].push(4);
console.log(nums); // [[1, 4], 2, [3]]
// Array.prototype.join(separator)
// separator爲字符串,默認爲","
let str = nums.join(); // "1,4,2,3"
// Array.prototype.slice(begin, end)
// begin爲開始索引(包含),end爲結束索引(不包含)
let slcieArr = nums.slice(0,2); // [[1, 4], 2]
// Array.prototype.toString()
let toStringArr = nums.toString(); // "1,4,2,3"
ES5數組方法:
方法 | 描述 |
---|---|
Array.prototype.forEach() | 對數組的每個元素執行一次提供的函數。跳過空位元素 |
Array.prototype.every() | 如果數組中的每個元素都滿足測試函數,則返回 true,否則返回 false。跳過空位元素 |
Array.prototype.some() | 如果數組中至少有一個元素滿足測試函數,則返回 true,否則返回 false。跳過空位元素 |
Array.prototype.map() | 返回一個由回調函數的返回值組成的新數組。不改變原數組,跳過空位元素 |
Array.prototype.filter() | 將所有在過濾函數中返回 true 的數組元素放進一個新數組中並返回。不改變原數組,跳過空位元素 |
Array.prototype.reduce() | 從左到右爲每個數組元素執行一次回調函數,並把上次回調函數的返回值放在一個暫存器中傳給下次回調函數,並返回最後一次回調函數的返回值。跳過空位元素 |
Array.prototype.reduceRight() | 從右到左爲每個數組元素執行一次回調函數,並把上次回調函數的返回值放在一個暫存器中傳給下次回調函數,並返回最後一次回調函數的返回值。跳過空位元素 |
Array.prototype.indexOf() | 返回數組中第一個與指定值相等的元素的索引,如果找不到這樣的元素,則返回 -1。 |
Array.prototype.lastIndexOf() | 返回數組中最後一個(從右邊數第一個)與指定值相等的元素的索引,如果找不到這樣的元素,則返回 -1。 |
// 遍歷方法
// Array.prototype.forEach(callback(element[, index[, array]])[, thisArg])
// 沒有辦法中止或者跳出 forEach 循環,除了拋出一個異常。
// 使用箭頭函數表達式傳入函數參數,thisArg 參數會被忽略
// 使用forEach方法按索引每秒輸出一個元素
let data = [1,2,3,4,5];
data.forEach((val,index) => {
setTimeout(() => {
console.log(val);
},1000*index);
});
// Array.prototype.every(callback(element[, index[, array]])[, thisArg])
// 判斷data中的元素的值是否都小於6
data.every((val) => {
return val < 6;
}); // true
// Array.prototype.some(callback(element[, index[, array]])[, thisArg])
// 判斷data中是否存在元素的值大於6
data.some((val) => {
return val > 6;
}); // false
// Array.prototype.map(callback(element[, index[, array]])[, thisArg])
// 返回一個元素爲data數組對應索引的元素值的平方的新數組
data.map((val) => {
return val**2;
}); // [1, 4, 9, 16, 25]
// 對稀疏數組中的空缺元素不執行操作,但不在新數組中剔除
let sparseArray = [1,,3,,5];
sparseArray.map((val) => {
return val++;
}); // [1, empty, 9, empty, 25]
// map會默認傳遞3個參數
["1", "2", "3"].map(parseInt); // [1, NaN, NaN]
// Array.prototype.filter(callback(element[, index[, array]])[, thisArg])
// 返回data數組中奇數元素組成的數組
data.filter((val) => {
return val % 2 == 1;
}); // [1, 3, 5]
// filter()返回的新數組總是稠密的
// 剔除數組中的空缺元素
sparseArray.filter((val) => {
return true;
}); // [1, 3, 5]
// Array.prototype.reduce(callback(accumulator[, currentValue[, currentIndex[, array]]])[, initialValue])
// 數組求和
let sum = data.reduce((x,y) => {
return x + y;
},0) // 15
// 數組求積
let product = data.reduce((x,y) => {
return x * y;
},1) // 120
// 求最大值
let max = data.reduce((x,y) => {
return x > y ? x : y;
},1) // 5
let a = [0,1,2,1,0]
// Array.prototype.indexOf(searchElement, fromIndex)
a.indexOf(1,0); // 1
// Array.prototype.lastIndexOf(searchElement, fromIndex)
a.lastIndexOf(1,0); // 3
// 沒有找到則返回-1
a.indexOf(3,0); // -1
ES6 數組擴展
// 擴展運算符
const spreadArr = [1, ...[2, 3, 4], 5]; // [1, 2, 3, 4, 5 ]
// 擴展運算符後面是一個空數組,則不產生任何效果
const emptySpread = [...[], 1]; // [1]
// 將一個數組,變爲參數序列
emptySpread.push(...[2, 3, 4]); // [1, 2, 3, 4]
// 複製數組
const [...sparseArray1] = sparseArray; // [1, 2, 3, 4, 5 ]
const sparseArray2 = [...sparseArray]; // [1, 2, 3, 4, 5 ]
// 合併數組 同sparseArray1.concat(sparseArray2) 淺拷貝
[...sparseArray1, ...sparseArray2] // [1, 2, 3, 4, 5, 1, 2, 3, 4, 5 ]
// 與解構賦值結合
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
// 如果將擴展運算符用於數組賦值,只能放在參數的最後一位,否則會報錯。
const [...butLast, last] = [1, 2, 3, 4, 5]; // Uncaught SyntaxError: Rest element must be last element
// 字符串
// 正確識別四個字節的 Unicode 字符。
let doubleWordStrLen1 = 'x\uD83D\uDE80y'.length; // 4
let doubleWordStrLen2 =[...'x\uD83D\uDE80y'].length; // 3
// Generator 函數可以使用擴展運算符 如Map()、Set()
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let arr = [...map.keys()]; // [1, 2, 3]
可將僞數組對象(array-like object
)和可迭代對象(iterable
)(包括 ES6
新增的數據結構 Set
和 Map
)轉換爲數組。
// Array.from(arrayLike[, mapFn[, thisArg]])
// 不支持ES6可用Array.prototype.slice方法替代
// 將類數組轉換爲數組
// NodeList對象
let ps = document.querySelectorAll('p');
Array.from(ps).filter(p => {
return p.textContent.length > 100;
});
// arguments對象
function foo() {
var args = Array.from(arguments);
// ...
}
// 與擴展運算符區別
Array.from({ length: 3 }); // [ undefined, undefined, undefined ]
// 數組去重
Array.from(new Set([1, 2, 3, 2, 1])); // [1, 2, 3]
// 返回各種數據的類型。
function typesOf () {
return Array.from(arguments, value => typeof value)
}
typesOf(null, [], NaN); // ['object', 'object', 'number']
Array.of()
方法用於將一組值,轉換爲數組。
// Array.of(element0[, element1[, ...[, elementN]]])
// 實現
function ArrayOf(){
return [].slice.call(arguments);
}
// 彌補數組構造函數Array()的不足
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
copyWithin()
方法淺複製數組的一部分到同一數組中的另一個位置,並返回它,而不修改其大小。
// Array.prototype.copyWithin(target, start = 0, end = this.length)
// 將3號位複製到0號位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
// -2相當於3號位,-1相當於4號位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
// 將3號位複製到0號位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}
// 將2號位到數組結束,複製到0號位
let i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
// 對於沒有部署 TypedArray 的 copyWithin 方法的平臺
// 需要採用下面的寫法
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
Array.prototype.find() & Array.prototype.findIndex()
find()
方法返回數組中滿足提供的測試函數的第一個元素的值。否則返回 undefined。
findIndex()
方法返回數組中滿足提供的測試函數的第一個元素的索引。否則返回-1。
// Array.prototype.find(callback(element[, index[, array]])[, thisArg])
// 找出數組中第一個小於 0 的成員。
[1, 4, -5, 10].find((n) => n < 0); // -5
// Array.prototype.findIndex(callback(element[, index[, array]])[, thisArg])
// 找出數組中第一個小於 0 的成員索引。
[1, 4, -5, 10].findIndex((n) => n < 0); // 2
// 兩個方法都可以發現NaN,彌補了數組的indexOf方法的不足
[NaN].indexOf(NaN); // -1
[NaN].findIndex(y => Object.is(NaN, y)); // 0
fill()
方法用一個固定值填充一個數組中從起始索引到終止索引內的全部元素。
// Array.prototype.fill(value, start=0, end=this.length)
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
Array.prototype.entries() & Array.prototype.keys() & Array.prototype.values()
ES6
提供三個新的方法——entries()
,keys()
和values()
——用於遍歷數組。它們都返回一個遍歷器對象(Array Iterator
對象),可以用for...of
循環進行遍歷,唯一的區別是keys()
是對鍵名的遍歷、values()
是對鍵值的遍歷,entries()
是對鍵值對的遍歷。
// Array.prototype.entries() & Array.prototype.keys() & Array.prototype.values()
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"
// 不使用for...of循環,可以手動調用遍歷器對象的next方法,進行遍歷。
let letter = ['a', 'b', 'c'];
let entries = letter.entries();
console.log(entries.next().value); // [0, 'a']
console.log(entries.next().value); // [1, 'b']
console.log(entries.next().value); // [2, 'c']
includes()
方法用來判斷一個數組是否包含一個指定的值,根據情況,如果包含則返回 true
,否則返回false
。
// Array.prototype.includes(searchElement, fromIndex)
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
// 與indexOf()區別
[NaN].indexOf(NaN); // -1
[NaN].includes(NaN); // true
參考資料:
MDN Array
ECMAScript 6 入門 阮一峯
《JavaScript權威指南》第6版