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版