一、Array 对象
Array 对象用于在变量中存储多个值;数组是一种具有相同类型值的集合,它的每一个值称为数组的一个元素。数组用于在内存中存储大量相同类型的数据,可以通过数组的名称和下标来访问数组中的元素。
二、数组属性
属 性 | 含 义 |
---|---|
constructor | 引用数组对象的构造函数 |
length | 返回数组元素的个数。如果在创建数组时指定了数组的长度,那么无论数组元素中是否超出了实际数据,该属性的值都是这个指定的长度值 |
prototype | 用于在定义数组时添加新的属性和方法。Prototype 是数组对象的静态属性。 |
三、Array对象方法
序 号 | 方法 | 描述 |
---|---|---|
1 | concat() | 连接两个或更多的数组,并返回结果; |
2 | conpyWithin() | 浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度; |
3 | entries() | 从原数组创建一个可迭代对象, 该对象包含了数组的键/值对 |
4 | every() | 测试一个数组内的元素是否都能通过某个指定函数的测试,返回一布尔值; |
5 | fill() | 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引; |
6 | filter() | 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素 |
7 | find() | 返回数组中满足提供的测试函数的第一个元素的值,否则返回 undefined |
8 | findIndex() | 返回数组中满足提供的测试函数的第一个元素的索引,否则返回-1 |
9 | flat() | 按照一个可指定的深度递归遍历数组,将嵌套数组和原数组组合成一维数组返回; |
10 | flatMap() | 首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些; |
11 | forEach() | 对数组的每个元素都执行一次回调函数; |
12 | from() | 从一个类似数组或可迭代的对象中创建一个新的、浅拷贝的数组实例; |
13 | includes() | 判断一个数组是否包含一个指定的值,包含则返回 true,否则返回false; |
14 | indexOf() | 在数组中找到给定的元素的第一个索引,如果找不到,则返回-1。 |
15 | isArray() | 判断对象是否为数组; |
16 | join() | 把数组的所有元素放入一个字符串; |
17 | keys() | 返回数组的可迭代对象,包含原始数组的键(key); |
18 | lastIndexOf() | 搜索数组中的元素,并返回它最后出现的位置索引,没有则返回-1; |
19 | map() | 通过指定函数处理数组的每个元素,并返回处理后的数组; |
20 | pop() | 删除数组的最后一个元素并返回删除的元素; |
21 | push() | 向数组的末尾添加一个或更多元素,并返回新的长度; |
22 | reduce() | 将数组元素计算为一个值(从左到右); |
23 | reduceRight() | 将数组元素计算为一个值(从右到左); |
24 | reverse() | 反转数组的元素顺序; |
25 | shift() | 删除并返回数组的第一个元素; |
26 | slice() | 选取数组的的一部分,并返回一个新数组; |
27 | some() | 检测数组元素中是否有元素符合指定条件; |
28 | sort() | 对数组的元素进行排序; |
29 | splice() | 从数组中添加或删除元素; |
30 | toString() | 把数组转换为字符串,并返回结果; |
31 | unshift() | 向数组的开头添加一个或更多元素,并返回新的长度; |
32 | values() | 返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值; |
具体用法:
1、concat() 的使用
用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组
语法: var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
参数:
|---valueN 可选,将数组和/或值连接成新数组。详情请参阅下文描述;返回值:
|---新的Array实例。
合并三个数组的值
var arr1 = ["A", "B"];
var arr2 = ["a", "b", "c"];
var arr3 = ["Aa"];
var arr4 = t1.concat(t2,t3);
结果:
arr4 = ["A", "B", "a", "b", "c", "Aa"]
2、conpyWithin() 的使用
浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
语法:arr.copyWithin(target[, start[, end]])
参数:
|--- target:复制序列开始的位置(即,原数据保留的元素位置),负数target 将从末尾开始计算,如果 target 大于等于 arr.length,将会不发生拷贝;
|--- start:复制元素的起始位置。如果是负数,start 将从末尾开始计算,如果 start 被忽略,将会从0开始复制;
|--- end:复制元素的结束位置,将会拷贝到该位置,但不包括 end 这个位置的元素。如果是负数,将从末尾开始计算,如果 end 被忽略,将会一直复制至数组结尾;返回值:
|--- 改变后的数组。
实例:Array.conpyWithin()
let numbers = [1, 2, 3, 4, 5];
numbers.copyWithin(-2);
// [1, 2, 3, 1, 2]
numbers.copyWithin(0, 3);
// [4, 5, 3, 4, 5]
numbers.copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]
numbers.copyWithin(-2, -3, -1);
// [1, 2, 3, 3, 4]
3、entries() 的使用
从数组 arr 创建一个可迭代对象, 该对象包含了数组的键值对
语法:arr.entries()
返回值:
|--- 一个新的 Array迭代器对象。Array Iterato是对象,它的原型(proto:Array Iterator)上有一个next 方法,可用用于遍历迭代器取得原数组的[key,value]。
实例1:Array.entries()
var array1 = ['a', 'b', 'c'];
var iterator1 = array1.entries();
console.log(iterator1.next().value);
// [0, "a"]
console.log(iterator1.next().value);
// [1, "b"]
实例2:iterator.next()
var arr = ["a", "b", "c"];
var iterator = arr.entries();
console.log(iterator.next());
/*{value: Array(2), done: false}
done:false
value:(2) [0, "a"]
__proto__: Object
*/
// iterator.next()返回一个对象,对于有元素的数组,
// 是next{ value: Array(2), done: false };
// next.done 用于指示迭代器是否完成:在每次迭代时进行更新而且都是false,
// 直到迭代器结束done才是true。
// next.value是一个["key","value"]的数组,是返回的迭代器中的元素值。
实例3:iterator.next方法运行
var arr = ["a", "b", "c"];
var iter = arr.entries();
var a = [];
// for(var i=0; i< arr.length; i++){ // 实际使用的是这个
for(var i=0; i< arr.length+1; i++){ // 注意,是length+1,比数组的长度大
var tem = iter.next(); // 每次迭代时更新next
console.log(tem.done); // 这里可以看到更新后的done都是false
if(tem.done !== true){ // 遍历迭代器结束done才是true
console.log(tem.value);
a[i]=tem.value;
}
}
console.log(a); // 遍历完毕,输出next.value的数组
结果:
false
[0, "a"]
false
[1, "b"]
false
[2, "c"]
true
(3) [Array(2), Array(2), Array(2)]
0: (2) [0, "a"]
1: (2) [1, "b"]
2: (2) [2, "c"]
length: 3
__proto__: Array(0)
实例4:二维数组按行排序
function sortArr(arr) {
var goNext = true;
var entries = arr.entries();
while (goNext) {
var result = entries.next();
if (result.done !== true) {
result.value[1].sort((a, b) => a - b);
goNext = true;
} else {
goNext = false;
}
}
return arr;
}
var arr = [[1,34],[456,2,3,44,234],[4567,1,4,5,6],[34,78,23,1]];
sortArr(arr);
/*(4) [Array(2), Array(5), Array(5), Array(4)]
0:(2) [1, 34]
1:(5) [2, 3, 44, 234, 456]
2:(5) [1, 4, 5, 6, 4567]
3:(4) [1, 23, 34, 78]
length:4
__proto__:Array(0)
*/
实例5:使用 for…of 循环
var arr = ["a", "b", "c"];
var iterator = arr.entries();
// undefined
for (let e of iterator) {
console.log(e);
}
// [0, "a"]
// [1, "b"]
// [2, "c"]
4、every() 的使用
测试一个数组内的所有元素是否都能通过某个指定函数的测试,返回一个布尔值;
注意:若收到一个空数组,此方法在一切情况下都会返回 true
语法:arr.every(callback[, thisArg])
参数:
|---callback:用来测试每个元素的函数,它可以接收三个参数:
|--- currentValue: 用于测试的当前值;
|--- index: 可选,用于测试的当前值的索引;
|--- array: 可选,调用 every 的当前数组;
|---thisArg:执行 callback 时使用的 this 值;返回值:
|---如果回调函数的每一次返回都为 truthy 值,返回 true ,否则返回 false。
说明:
every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
- 如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
- 如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。
实例1:检测所有数组元素的大小
//检测数组中的所有元素是否都大于 10
function isBigEnough(currentValue, index, array) {
return element >= 10;
}
[12, 5, 8, 130, 44].every(isBigEnough); // false
[12, 54, 18, 130, 44].every(isBigEnough); // true
实例2:使用箭头函数
[12, 5, 8, 130, 44].every(x => x >= 10); // false
[12, 54, 18, 130, 44].every(x => x >= 10); // true
5、fill() 的使用
用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引;
语法:arr.fill(value[, start[, end]])
参数:
|---value:用来填充数组元素的值;
|---start:可选,起始索引,默认值为0;
|---end:可选,终止索引,默认值为 this.length;返回值:
|--- 修改后的数组。
实例1:
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
// Objects by reference.
var arr = Array(3).fill({}) // [{}, {}, {}];
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]
6、filter() 的使用
filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素
语法:var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
参数:
|---callback:用来测试每个元素的函数,它可以接收三个参数:
|--- currentValue:数组中当前正在处理的值;
|--- index: 可选,正在处理的元素在数组中的索引;
|--- array: 可选,调用了 filter 的数组本身;
|---thisArg:可选,执行 callback 时,用于 this 的值;返回值:
|---一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。
实例1:筛选排除所有较小的值
function isBigEnough(element) {
return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// [12, 130, 44]
//回调函数箭头函数写法
var filtered2 = [12, 5, 8, 130, 44].filter((element)=> element >= 10);
// [12, 130, 44]
实例2:过滤 JSON 中的无效条目
//使用 filter() 创建具有非零 id 的元素的 json
var arr = [
{ id: 15 },
{ id: -1 },
{ id: 0 },
{ id: 3 },
{ id: 12.2 },
{ },
{ id: null },
{ id: NaN },
{ id: 'undefined' }
];
var invalidEntries = 0;
function isNumber(obj) {
return obj !== undefined && typeof(obj) === 'number' && !isNaN(obj);
}
function filterByID(item) {
if (isNumber(item.id) && item.id !== 0) {
return true;
}
invalidEntries++;
return false;
}
var arrByID = arr.filter(filterByID);
console.log('过滤后的数组:\n', arrByID);
// Filtered Array
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]
console.log('无效的条目数 = ', invalidEntries);
// 无效的条目数 = 5
/*******************************************************************************************/
//用箭头函数简化代码,如下
var invalidEntries2 = 0;
var arrByID2 = arr.filter((item) =>
item.id !== undefined && typeof(item.id ) === 'number' && !isNaN(item.id ) && item.id !== 0 ?
true : (invalidEntries2++,false)
);
console.log('\n过滤后的数组2:\n', arrByID2);
// Filtered Array
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]
console.log('无效的条目数2 = ', invalidEntries2);
// 无效的条目数 = 5
实例3:在数组中搜索
//使用 filter() 根据搜索条件来过滤数组内容
var fruits = ['apple', 'banana', 'grapes', 'mango', 'orange'];
/**
* Array filters items based on search criteria (query)
*/
function filterItems(query) {
return fruits.filter(function(el) {
return el.toLowerCase().indexOf(query.toLowerCase()) > -1;
})
}
console.log(filterItems('ap')); // ['apple', 'grapes']
console.log(filterItems('an')); // ['banana', 'mango', 'orange']
/*************************************************************************************/
//箭头函数写法
const filterItems2 = (query) => {
return fruits.filter((el) =>
el.toLowerCase().indexOf(query.toLowerCase()) > -1
);
}
console.log(filterItems2('ap')); // ['apple', 'grapes']
console.log(filterItems2('an')); // ['banana', 'mango', 'orange']
7、find() 的使用
find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
。
语法:arr.find(callback[, thisArg])
参数:
|--- callback:在数组每一项上执行的函数,接收 3 个参数:
|--- currentValue:当前遍历到的元素;
|--- index: 可选,当前遍历到的索引;
|--- array: 可选,数组本身;
|---thisArg:执行回调时用作this 的对象;返回值:
|--- 数组中第一个满足所提供测试函数的元素的值,否则返回 undefined。
实例1:用对象的属性查找数组里的对象
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
function findCherries(fruit) {
return fruit.name === 'cherries';
}
console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }
/********************************************************************************/
//箭头函数简化写法
console.log(inventory.find((fruit)=>fruit.name === 'cherries'));
实例2:寻找数组中的质数
//如何从一个数组中寻找质数(如果找不到质数则返回undefined)
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) {
return false;
}
}
return element > 1;
}
console.log([4, 6, 8, 12].find(isPrime)); // undefined, not found
console.log([4, 5, 8, 12].find(isPrime)); // 5
/*****************************************************************************/
console.log([4, 5, 8, 12].find((item)=>{
var st = 2;
while (st <= Math.sqrt(item)){
if (item % st++ < 1) {
return false;
}
}
return item > 1;
})); // 5
8、findIndex() 的使用
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1
语法:arr.findIndex(callback[, thisArg])
参数:
|--- callback:针对数组中的每个元素, 都会执行该回调函数, 执行时会自动传入下面三个参数:
|--- currentValue:当前的元素;
|--- index: 当前元素的索引;
|--- array: 调用findIndex的数组;
|---thisArg:可选。执行callback时作为this对象的值;
实例1:查找数组中首个质数元素的索引
//查找数组中素数的元素的索引(如果不存在素数,则返回-1)。
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) {
return false;
}
}
return element > 1;
}
console.log([4, 6, 8, 12].findIndex(isPrime)); // -1, not found
console.log([4, 6, 7, 12].findIndex(isPrime)); // 2
9、flat() 的使用
按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回;
语法:var newArray = arr.flat(depth)
参数:
|--- depth:可选。指定要提取嵌套数组的结构深度,默认值为 1返回值:
|--- 一个包含将数组与子数组中所有元素的新数组。
实例1:扁平化嵌套数组
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]
实例2:扁平化嵌套数组
//flat() 方法会移除数组中的空项
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]
替代方案
实例3:使用 reduce 与 concat 替代
var arr = [1, 2, [3, 4]];
console.log(arr.flat()); // [1, 2, 3, 4]
// 反嵌套一层数组
var newArr = arr.reduce((acc, val) => acc.concat(val), []);
console.log(newArr); // [1, 2, 3, 4]
// 或使用 ...
console.log( [].concat(...arr) ); // [1, 2, 3, 4]
// 使用 reduce、concat 和递归无限反嵌套多层嵌套的数组
var arr = [1,2,3,[1,2,3,4, [2,3,4]]];
//使用flat
console.log(arr.flat(Infinity)); // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
//使用reduce 和 concat
function flattenDeep(arr) {
return arr.reduce((acc, val) => Array.isArray(val) ?
acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
console.log(flattenDeep(arr)); // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
10、flatMap() 的使用
首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 以及 深度值为1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些;
语法:var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {
// 返回新数组的元素
}[, thisArg])参数:
|--- callback:可以生成一个新数组中的元素的函数,可以传入三个参数:
|--- currentValue:当前正在数组中处理的元素;
|--- index: 可选的。数组中正在处理的当前元素的索引;
|--- array: 可选的。被调用的 map 数组;
|---thisArg:可选的。执行 callback 函数时 使用的this 值;返回值:
|--- 一个新的数组,其中每个元素都是回调函数的结果,并且结构深度 depth 值为1。
实例1:Map 与 flatMap
var arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
// 只会将 flatMap 中的函数返回的数组 “压平” 一层
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
虽然上面的代码使用 map 和 flatMap 好像都可以,但这只能展示如何使用 flatMap。
所以,为了更好的展示 flatMap 的作用,下面我们将包含几句话的数组拆分成单个汉字组成的新数组。
let arr = ["今天天气不错", "", "早上好"]
arr.map(s => s.split(""))
// [["今", "天", "天", "气", "不", "错"],[""],["早", "上", "好"]]
arr.flatMap(s => s.split(''));
// ["今", "天", "天", "气", "不", "错", "早", "上", "好"]
等价操作:
//使用 reduce 与 concat
var arr1 = [1, 2, 3, 4];
arr1.flatMap(x => [x * 2]);
// 等价于
arr1.reduce((acc, x) => acc.concat([x * 2]), []);
// [2, 4, 6, 8]
后文,继续......