当前位置: 首页 > news >正文

JavaScript手录07-数组

画板

数组是 JavaScript 中最常用的数据结构之一,用于存储有序的集合数据。它具有灵活、易用的特点,支持多种操作方法。以下是 JavaScript 数组的核心知识:

一、数组的基本概念

数组是**有序的元素集合**,元素可以是任意数据类型(数字、字符串、对象、甚至其他数组等),并且长度可以动态变化。

1. 数组的创建方式
// 1. 数组字面量(最常用)
const arr1 = [1, 2, 3];
const arr2 = ['a', true, { name: '张三' }, [4, 5]]; // 元素类型不限// 2. 构造函数 Array()
const arr3 = new Array(1, 2, 3); // 等价于 [1,2,3]
const arr4 = new Array(5); // 创建长度为5的空数组(元素为 undefined)// 3. Array.of()(ES6+,解决 new Array 单参数的歧义)
const arr5 = Array.of(5); // [5](直接将参数作为元素)
const arr6 = Array.of(1, 2, 3); // [1,2,3]
2. 数组的索引与长度
  • 索引:数组元素的位置编号,从 0 开始(负数和非整数索引会被当作对象属性处理,不计算在数组长度内)。
  • 长度(length):数组的 length 属性表示元素个数,可读写(修改 length 可截断或扩展数组)。
const arr = [10, 20, 30];
console.log(arr[0]); // 10(访问索引0的元素)
console.log(arr.length); // 3(长度为3)// 修改 length 截断数组
arr.length = 2;
console.log(arr); // [10, 20]// 修改 length 扩展数组(新增元素为 undefined)
arr.length = 4;
console.log(arr); // [10, 20, undefined, undefined]

二、数组的常用方法

数组提供了大量内置方法,按功能可分为修改原数组返回新数组两类。以及数组的遍历/迭代方法与ES6+ 新增的一些实用方法。

修改原数组的方法(会改变原数组)【7个】

以下这些方法会直接修改调用它们的数组本身,返回值通常与修改结果相关。

push(…elements)
push(...elements)
功能向数组末尾添加一个或多个元素
参数...elements(要添加的元素)
返回值添加元素后数组的新长度

示例:

// push()方法
let arr = [1,2,3,4,5]
let len = arr.push(5,6)
console.log(arr);
console.log(len);
pop()
pop()
功能删除数组的最后一个元素
参数
返回值被删除的元素;如果数组为空,则返回undefined

示例:

// pop()方法
let arr = [1,2,3,4,5]
console.log(arr.length); // 5
let popItem = arr.pop()
console.log(arr); // [1,2,3,4]
console.log(popItem); // 5
console.log(arr.length); // 4
unshift(…elements)
unshift(...elements)
功能向数组开头添加一个或多个元素
参数...elements(要添加的元素)
返回值添加元素后数组的新长度

示例:

// unshift()方法
let arr = [1,2,3,4,5]
console.log(arr.length); // 5
let len = arr.unshift(-1,0)
console.log(arr); // [-1,0,1,2,3,4,5]
console.log(len); // 7
shift()
shift()
功能删除数组的第一个元素
参数
返回值被删除的元素;如果数组为空,则返回undefined

示例:

// shift()方法
let arr = [1,2,3]
let shiftItem = arr.shift()
console.log(arr); // [2,3]
console.log(shiftItem); // 1
splice(start[, deleteCount[, …items]])
splice(start, [, deleteCount[, ...items]])
功能从指定位置删除、添加或者替换元素(最灵活的修改方法)
参数+ start:起始索引(可以为负数,如果为负数则从末尾开始计算;)
+ deleteCount (可选):要删除的元素数量(如果为 0 则不删除元素)
+ ...items (可选):要添加到数组的元素,从start位置开始插入
返回值被删除的元素组成的新数组;如果没有删除元素,则返回空数组。

示例:

// splice(start,deleteCount,...items)方法
// 删除元素
let arr = [1,2,3,4,5]
let delArr = arr.splice(2,2)
console.log(arr);
console.log(delArr);
// 添加元素
arr.splice(2,0,...delArr)
console.log(arr);
// 替换元素
arr.splice(2,2,-3,-4)
console.log(arr);
// 从末尾删除元素
arr.splice(-3,3)
console.log(arr);
reverse()
reverse()
功能反转数组元素的顺序
参数
返回值反转后的新数组

示例:

// reverse()方法
let arr = [1,2,3]
console.log(arr.reverse()); // [3,2,1]
sort([compareFunction])
sort([compareFunction])
功能对数组元素进行排序(默认按照字符串Unicode编码排序)
参数+ compareFunction (可选):自定义排序规则的函数,格式为(a, b) => { ... }
+ 如果返回值<0:则 a 排在 b 前面
+ 如果返回值=0:则 a 和 b 位置不变
+ 如果返回值>0:则 b 排在 a 前面
返回值排序后的新数组

示例:

// sort([compareFunction])方法
// 默认排序
let arr = ['a', 'c', 'b', 'e', 'd']
// console.log(arr.sort());
// 升序
let numArr = [3,6,78,9,6,10]
numArr.sort((a,b) => { return a-b })
console.log(numArr);
// 降序
let numArr2 = [3,6,7,9,6,10]
numArr2.sort((a,b) => { return b-a })
console.log(numArr2);
不修改原数组的方法(返回新结果,原数组不变)【7个】

以下这些方法不会修改原数组,而是返回新的数组、字符串或者其他值。

concat(…arrays)
concat(...arrays)
功能合并两个或多个数组(或值),返回合并后的新数组
参数...arrays(要合并的数组或值,可以是单个元素,也可以是数组)
返回值合并后的新数组

示例:

// concat()方法
let arr = [1,2,3]
let arr2 = [3,4,5]
let item = 6
let newArr = arr.concat(arr2,item)
console.log(newArr);
slice(start,[,end])
slice(start,[,end])
功能从数组中提取子数组,从startend前一位;左开右闭;不包括end
参数+ start:起始索引,可为负数;如果为负数,则从末尾计算。(按照数组索引从0开始计算)
+ end(可选):结束索引,默认到数组末尾;如果为负数,则从末尾计算。
返回值返回提取到的新数组,原数组不变

示例:

// slice方法
let arr = [1,2,3,4,5]
let newArr = arr.slice(2, -1)
console.log(newArr); // [3,4]
join([separator])
join([separator])(separator意为分隔符)
功能将数组元素拼接为字符串(默认用英文逗号分隔)
参数separator(可选)分隔符(默认为英文逗号)
返回值拼接后的字符串

示例:

// join()方法
let arr = ['h','e','l','l','o','!']
let str = arr.join('-')
console.log(str);
indexOf(searchElement[, formIndex])
indexOf(searchElement[,formIndex])
功能从前往后查找元素中数组中的第一个索引
参数+ searchElement:要查找的元素
+ formIndex(可选):起始查找索引(默认为0)
返回值如果查找到目标元素,则返回索引;否则,返回-1
注:查找采用===比较,无法识别NaN``[NaN].indexOf(NaN) => -1

示例:

// indexOf(searchElement[,formIndex])
let arr = [1,2,3,4,5]
let index = arr.indexOf(5)
let index2 = arr.indexOf(NaN)
console.log(index); // 4
console.log(index2); // -1
lastIndexOf(searchElement[,formIndex])
lastIndexOf(searchElement[,formIndex])
功能从后往前查找目标元素中数组中的最后一个索引
参数+ searchElement:要查找的元素
+ formIndex(可选):起始查找索引,默认为数组末尾
返回值如果查找到目标元素,则返回索引;否则,返回-1

示例:

// lastIndexOf(searchElement[,formIndex])
let arr = [1,2,3,4,4,4,5]
let index = arr.lastIndexOf(4)
console.log(index); // 5
includes(searchElement[,formIndex])
includex(searchElement[,formIndex])
功能判断数组是否包含某个元素
参数+ searchElement:要查找的元素
+ formIndex(可选):起始查找索引(默认为0)
返回值如果数组中包含目标元素,则返回true;否则,返回false
优势:可以识别NaN``[NaN].includes(NaN) => true

示例:

// includes(searchElement[, formIndex])
let arr = [1,2,3,4,5,'a','c','d',NaN]
let index = arr.includes(3)
let index2 = arr.includes('a')
let index3 = arr.includes(NaN)
console.log(index)  // true
console.log(index2)	// true
console.log(index3)	// true
toString()
toString()
功能将数组转为字符串(等价于join(),默认逗号分隔)
参数
返回值目标数组转换成的字符串

示例:

// toString() 方法
let arr = ['h','e','l','l','o']
let str = arr.toString()
console.log(str) // 'h,e,l,l,o'
数组的遍历/迭代方法(对数组中的每个元素进行操作)【9个】

这类方法用于遍历数组,通过回调函数处理数组中的每个元素。一般会返回新数组或者新值,不修改原数组。(除非在回调函数中主动修改了原数组)

forEach(callback[, thisArg])
forEach(callback[, thisArg])
功能遍历数组,对每个元素执行回调函数(无返回值)
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值
特点+ 无法通过return或者break中断循环(除非抛出异常)
+ 不修改原数组,除非中回调中主动修改

示例:

// forEach()方法let arr = [1,2,3,4,5]arr.forEach((item, index) => {console.log(item + '-' + index);})
map(callback[, thisArg])
map(callback[, thisArg])
功能遍历数组,对数组中的每个元素执行回调函数
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值新数组,长度与原数组相同,新数组的元素为回调函数返回值

示例:

 // map(callback[, thisArg])
let arr = [1,2,3,4,5]
let newArr = arr.map((item, index) => item + 1)
console.log(newArr); // [2,3,4,5,6]
filter(callback[, thisArg])
filter(callback[, thisArg])
功能遍历数组,筛选出符合条件的元素组成新数组
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值筛选后的新数组(可能为空)

示例:

// filter(callback[, thisArg])
let arr = [1,2,3,4,5]
let newArr = arr.filter((item, index) => item > 2)
console.log(newArr); // [3,4,5]
let newArr2 = arr.filter(item => item > 10)
console.log(newArr2); // []
find(callback[,thisArg])【ES6新增】
find(callback[,thisArg])
功能遍历数组,返回第一个符合条件的元素【ES6新增】
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值找到符合条件的第一个元素则返回该元素,否则返回undefined

示例:

// find(callback[, thisArg])
let arr = [1,2,3,4,5]
let item = arr.find(item => item > 3)
console.log(item); // 4
findIndex(callback[,thisArg])
findIndex(callback[,thisArg])
功能遍历数组,返回第一个符合条件的元素的索引【ES6新增】
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值如果查找到符合条件的第一个元素,则返回索引;否则,返回-1

示例:

// findIndex(callback[,thisArg])
let arr = [1,2,3,4,5]
let index = arr.findIndex(item => item > 2)
console.log(index);
some(callback[,thisArg])
some(callback[,thisArg])
功能判断数组中是否至少有一个符合条件的元素
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值<font style="color:rgb(0, 0, 0);">true</font><font style="color:rgb(0, 0, 0);">false</font>(一旦找到符合条件的元素,立即停止遍历)。

示例:

// some(callback[,thisArg])
let arr = [1,2,3,4,5]
let res = arr.some(item => item > 4)
console.log(res); // true
every(callback[,thisArg])
every(callback[,thisArg])
功能判断数组中是否所有元素都符合条件
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值<font style="color:rgb(0, 0, 0);">true</font><font style="color:rgb(0, 0, 0);">false</font>(一旦找到不符合条件的元素,立即停止遍历)。

示例:

// every(callback[,thisArg])
let arr = [1,2,3,4,5]
let res = arr.every(item => item > 0)
console.log(res); // true
reduce(callback[, initialValue])
reduce(callback[, initialValue])
功能对数组元素从左到右累计计算,返回累计结果。(非常灵活)
参数+ callback:累计函数,格式为(accumulator,currentValue,index,array) => {...}
- accumulator:累计器(上一次回调的返回值,或者初始值
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ initialValue(可选):初始值;如果不提供,则默认使用数组第一个元素作为初始值,从第二个元素开始遍历。
返回值最终的累计结果

示例:

// reduce(callback[,initialValue])
// 求和let arr1 = [1,2,3,4,5]let sum = arr1.reduce((acc,item)=>acc+item,0)console.log(sum);
// 求最大值let arr2 = [1,2,3,4,5]let max = arr2.reduce((max,item)=>max>item?max:item)console.log(max);
// 求最小值let arr3 = [1,2,3,4,5]let min = arr3.reduce((min,item)=>min<item?min:item)console.log(min);
// 去重let arr4 = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,6]let resArr = arr4.reduce((res, item) => {if(!res.includes(item)){res.push(item)}return res}, [])console.log(resArr);
reduceRight(callback[,intialValue])
reduceRight(callback[,intialValue])
功能reduce类似,但从右往左遍历数组
参数+ callback:累计函数,格式为(accumulator,currentValue,index,array) => {...}
- accumulator:累计器(上一次回调的返回值,或者初始值
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ initialValue(可选):初始值;如果不提供,则默认使用数组第一个元素作为初始值,从第二个元素开始遍历。
返回值最终的累计结果

示例:

// every(callback[,thisArg])
let arr = [1,2,3,4,5]
let res = arr.every(item => item > 0)
console.log(res); // true
ES6+ 新增方法(较新的实用方法)
flat(depth)
flat(depth)
功能将嵌套数组“扁平化”(展开深层数组)
参数depth(可选)扁平化的深度,默认为1(Infinity表示无限深度,完全扁平化)
返回值扁平化后的新数组,不修改原数组

示例:

const arr = [1, [2, [3, [4]]]];console.log(arr.flat()); // [1, 2, [3, [4]]](深度1)
console.log(arr.flat(2)); // [1, 2, 3, [4]](深度2)
console.log(arr.flat(Infinity)); // [1, 2, 3, 4](无限深度,完全扁平化)
flatMap(callback[,thisArg])
flatMap(callback[,thisArg])
功能先对数组执行 <font style="color:rgb(0, 0, 0);">map</font> 操作,再对结果执行 <font style="color:rgb(0, 0, 0);">flat(depth=1)</font>(等价于 <font style="color:rgb(0, 0, 0);">map(...).flat(1)</font>)。比 <font style="color:rgb(0, 0, 0);">map</font> 后再 <font style="color:rgb(0, 0, 0);">flat</font> 更高效。
参数+ callback:回调函数,格式为(currentValue,index,array) => {...}
- currentValue:当前元素
- index:当前元素的索引
- array:原数组
+ thisArg(可选):回调函数中this的指向
返回值操作完成后的新数组

示例:

const arr = ["hello world", "good morning"];
// 先split成数组,再扁平化(depth=1)
const words = arr.flatMap(str => str.split(" ")); 
console.log(words); // ["hello", "world", "good", "morning"]
// 等价于:arr.map(str => str.split(" ")).flat(1)
entries()、keys()、values()
#### <font style="color:rgb(0, 0, 0);">entries()</font><font style="color:rgb(0, 0, 0);">keys()</font><font style="color:rgb(0, 0, 0);">values()</font>
功能返回数组的 迭代器对象(可用于 <font style="color:rgb(0, 0, 0);">for...of</font> 循环)
简介+ <font style="color:rgb(0, 0, 0);">entries()</font>:返回 <font style="color:rgb(0, 0, 0);">[索引, 元素]</font> 形式的迭代器;
+ <font style="color:rgb(0, 0, 0);">keys()</font>:返回索引的迭代器;
+ <font style="color:rgb(0, 0, 0);">values()</font>:返回元素的迭代器。

示例:

const arr = ["a", "b"];// entries()
for (const [index, value] of arr.entries()) {console.log(index, value); // 0 "a";1 "b"
}// keys()
for (const key of arr.keys()) {console.log(key); // 0;1
}// values()
for (const value of arr.values()) {console.log(value); // "a";"b"
}
at(index)
at(index)
功能根据索引获取数组元素(支持 负索引,ES2022 新增)。
参数<font style="color:rgb(0, 0, 0);">index</font>:索引(正数从左数,负数从右数,<font style="color:rgb(0, 0, 0);">-1</font> 表示最后一个元素)。
返回值<font style="color:rgb(0, 0, 0);">index</font>对应的数组元素,类似于<font style="color:rgb(0, 0, 0);">arr[index]</font>,但支持负数索引。
注:比 <font style="color:rgb(0, 0, 0);">arr[index]</font> 更简洁地支持负索引(<font style="color:rgb(0, 0, 0);">arr[-1]</font> 不生效,而 <font style="color:rgb(0, 0, 0);">arr.at(-1)</font> 可行)。

示例:

const arr = [10, 20, 30];
console.log(arr.at(1)); // 20(同arr[1])
console.log(arr.at(-1)); // 30(最后一个元素,等价于arr[arr.length-1])
console.log(arr.at(-2)); // 20(倒数第二个元素)
数组的静态方法(Array构造函数上的方法)
Array.isArray(value)
Array.isArray(value)
功能判断一个值是否为数组(比 <font style="color:rgb(0, 0, 0);">typeof</font> 更可靠,<font style="color:rgb(0, 0, 0);">typeof []</font> 返回 <font style="color:rgb(0, 0, 0);">object</font>)。
参数value:要执行判断的目标
返回值<font style="color:rgb(0, 0, 0);">true</font><font style="color:rgb(0, 0, 0);">false</font>

示例:

console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false
console.log(Array.isArray("array")); // false
Array.from(arrayLike[, mapFn[, thisArg]])
Array.from(arrayLike[, mapFn[, thisArg]])
功能类数组对象(如 <font style="color:rgb(0, 0, 0);">arguments</font>、DOM 集合)或 可迭代对象(如 <font style="color:rgb(0, 0, 0);">Set</font><font style="color:rgb(0, 0, 0);">Map</font>)转为真正的数组。
参数+ <font style="color:rgb(0, 0, 0);">arrayLike</font>:类数组或可迭代对象;
+ <font style="color:rgb(0, 0, 0);">mapFn</font>(可选):类似 <font style="color:rgb(0, 0, 0);">map</font> 的回调函数,对每个元素处理后再返回;
+ <font style="color:rgb(0, 0, 0);">thisArg</font>(可选):<font style="color:rgb(0, 0, 0);">mapFn</font><font style="color:rgb(0, 0, 0);">this</font> 的指向。
返回值转化完成后的新数组

示例:

// 类数组转数组
const arrayLike = { 0: "a", 1: "b", length: 2 };
const arr = Array.from(arrayLike); 
console.log(arr); // ["a", "b"]// 带mapFn:转数组的同时处理元素
const nums = Array.from([1, 2, 3], x => x * 2); 
console.log(nums); // [2, 4, 6]
Array.of(…elements)
#### <font style="color:rgb(0, 0, 0);">Array.of(...elements)</font>
功能创建一个包含指定元素的数组(解决 <font style="color:rgb(0, 0, 0);">new Array()</font> 的怪异行为:<font style="color:rgb(0, 0, 0);">new Array(3)</font> 创建长度为 3 的空数组,而 <font style="color:rgb(0, 0, 0);">Array.of(3)</font> 创建 <font style="color:rgb(0, 0, 0);">[3]</font>)。

示例:

console.log(Array.of(1, 2, 3)); // [1, 2, 3]
console.log(Array.of(5)); // [5](对比new Array(5) → 长度5的空数组)

三、数组的特殊特性

  1. 稀疏数组:包含空元素的数组(索引不连续)。
const arr = [1, , 3]; // 索引1为空
console.log(arr.length); // 3(长度仍为3)
console.log(arr[1]); // undefined
  1. 数组与类数组:类数组(如 arguments、DOM 集合)具有 length 和索引,但没有数组方法,可通过 Array.from() 转换为数组。
const likeArr = { 0: 'a', 1: 'b', length: 2 };
const arr = Array.from(likeArr); // 转换为 ['a', 'b']
  1. 数组的引用类型特性:数组是引用类型,赋值和传递时操作的是引用地址。
const arr1 = [1, 2];
const arr2 = arr1; // 引用赋值
arr2.push(3);
console.log(arr1); // [1, 2, 3](原数组被修改)

练习

练习1:栈/队列模拟(<font style="background-color:#FBDE28;">push</font><font style="background-color:#FBDE28;">pop</font><font style="background-color:#FBDE28;">shift</font><font style="background-color:#FBDE28;">unshift</font>

目标:用数组模拟栈(后进先出)和队列(先进先出)的操作。

  • 栈:用 push(入栈)和 pop(出栈)实现,如 [1,2,3] 入栈 4 后为 [1,2,3,4],出栈后为 [1,2,3]
  • 队列:用 push(入队)和 shift(出队)实现,如 [1,2,3] 入队 4 后为 [1,2,3,4],出队后为 [2,3,4]

任务

  1. 创建一个空数组 stack,依次入栈 102030,再出栈一次,打印最终数组。
  2. 创建一个空数组 queue,依次入队 'a''b''c',再出队一次,打印最终数组。
练习2:数组截取与合并(<font style="background-color:#FBDE28;">slice</font><font style="background-color:#FBDE28;">concat</font>

目标:用 slice 截取子数组,用 concat 合并数组(均不修改原数组)。

任务
已知数组 const arr = [1, 2, 3, 4, 5]

  1. slice 截取索引 14(不含4)的子数组,结果应为 [2,3]
  2. concat 将子数组与 [6,7] 合并,结果应为 [2,3,6,7]
练习3:数组转换(<font style="background-color:#FBDE28;">map</font>

目标:用 map 将数组按规则转换(返回新数组,长度不变)。

任务

  1. 将数字数组 [1, 2, 3, 4] 转换为每个元素的平方组成的数组,结果 [1,4,9,16]
  2. 将对象数组 [{name: '张三', age: 18}, {name: '李四', age: 20}] 转换为仅包含姓名的数组,结果 ['张三', '李四']
练习4:数组筛选(<font style="background-color:#FBDE28;">filter</font>

目标:用 filter 筛选出符合条件的元素(返回新数组,长度可能减少)。

任务

  1. [5, 2, 9, 1, 5, 6] 中筛选出大于 5 的元素,结果 [9,6]
  2. 从对象数组 [{id: 1, done: true}, {id: 2, done: false}, {id: 3, done: true}] 中筛选出 donetrue 的对象,结果 [{id:1,...}, {id:3,...}]
练习5:数组判断(<font style="background-color:#FBDE28;">some</font><font style="background-color:#FBDE28;">every</font>

目标:用 someevery 判断数组元素是否符合条件。

任务

  1. 判断 [2,4,6,7] 中是否有奇数(some),结果应为 true(7是奇数)。
  2. 判断 [2,4,6,7] 中是否全是偶数(every),结果应为 false
  3. 判断对象数组 [{score: 60}, {score: 80}, {score: 90}] 中是否所有分数都 ≥60(every),结果 true
练习6:数组聚合(<font style="background-color:#FBDE28;">reduce</font>

目标:用 reduce 实现数组的求和、求平均值、去重等聚合操作。

任务

  1. [1,2,3,4,5] 的总和,结果 15
  2. [1,2,3,4,5] 的平均值,结果 3
  3. [1,2,2,3,3,3] 去重,结果 [1,2,3]
  4. 将对象数组 [{name: 'a', count: 2}, {name: 'b', count: 3}]count 累加,结果 5
练习7:数组排序(<font style="background-color:#FBDE28;">sort</font>

目标:用 sort 对数组进行排序,掌握自定义排序规则。

任务

  1. [3,1,4,2] 进行升序排序,结果 [1,2,3,4]
  2. [3,1,4,2] 进行降序排序,结果 [4,3,2,1]
  3. 对对象数组 [{name: '张三', age: 20}, {name: '李四', age: 18}]age 升序排序,结果 [李四(18), 张三(20)]
练习8:数组扁平化(<font style="background-color:#FBDE28;">flat</font><font style="background-color:#FBDE28;">flatMap</font>

目标:用 flatflatMap 处理嵌套数组。

任务

  1. [1, [2, [3, [4]]]] 完全扁平化,结果 [1,2,3,4](用 flat(Infinity))。
  2. ['hello world', 'good morning'] 先按空格拆分(split),再扁平化,结果 ['hello','world','good','morning'](用 flatMap)。
练习9:数组查找(<font style="background-color:#FBDE28;">indexOf</font><font style="background-color:#FBDE28;">find</font><font style="background-color:#FBDE28;">findIndex</font>

目标:用查找方法定位数组元素。

任务

  1. [10,20,30,20] 中找到 20 第一次出现的索引(indexOf),结果 1
  2. 在对象数组 [{id:1, name:'a'}, {id:2, name:'b'}] 中找到 id=2 的对象(find),结果 {id:2, name:'b'}
  3. [5,10,15,20] 中找到第一个大于 12 的元素的索引(findIndex),结果 2(元素15)。
练习10:综合练习(多方法组合)

目标:组合使用多种方法处理复杂场景。

任务
现有数组 const data = [ { name: '张三', score: 85, subject: '数学' }, { name: '张三', score: 90, subject: '语文' }, { name: '李四', score: 75, subject: '数学' }, { name: '李四', score: 80, subject: '语文' } ],完成以下操作:

  1. 筛选出数学成绩 ≥80 的记录(filter),结果应为 [{name: '张三', score:85, ...}]
  2. 提取所有学生的语文成绩,组成 [{name: '张三', score:90}, ...]filter + map)。
  3. 计算每个学生的平均分(reduce 分组聚合),结果 [{name: '张三', avg:87.5}, {name: '李四', avg:77.5}]

练习参考答案

练习1:栈/队列模拟(pushpopshiftunshift
// 1. 栈模拟(后进先出)
let stack = [];
stack.push(10); // 入栈:[10]
stack.push(20); // 入栈:[10, 20]
stack.push(30); // 入栈:[10, 20, 30]
stack.pop();    // 出栈:移除30,stack变为 [10, 20]
console.log("栈结果:", stack); // [10, 20]// 2. 队列模拟(先进先出)
let queue = [];
queue.push('a'); // 入队:['a']
queue.push('b'); // 入队:['a', 'b']
queue.push('c'); // 入队:['a', 'b', 'c']
queue.shift();   // 出队:移除'a',queue变为 ['b', 'c']
console.log("队列结果:", queue); // ['b', 'c']
练习2:数组截取与合并(sliceconcat
const arr = [1, 2, 3, 4, 5];// 1. 截取索引1到4(不含4)的子数组
const subArr = arr.slice(1, 3); // 从索引1开始,到索引3前结束(即1和2)
console.log("截取结果:", subArr); // [2, 3]// 2. 合并子数组与[6,7]
const mergedArr = subArr.concat([6, 7]);
console.log("合并结果:", mergedArr); // [2, 3, 6, 7]
练习3:数组转换(map
// 1. 数字数组转平方数组
const nums = [1, 2, 3, 4];
const squared = nums.map(num => num **2);
console.log("平方结果:", squared); // [1, 4, 9, 16]// 2. 对象数组提取姓名
const users = [{ name: '张三', age: 18 },{ name: '李四', age: 20 }
];
const names = users.map(user => user.name);
console.log("姓名数组:", names); // ['张三', '李四']
练习4:数组筛选(filter
// 1. 筛选大于5的元素
const numbers = [5, 2, 9, 1, 5, 6];
const greaterThan5 = numbers.filter(num => num > 5);
console.log("大于5的元素:", greaterThan5); // [9, 6]// 2. 筛选done为true的对象
const tasks = [{ id: 1, done: true },{ id: 2, done: false },{ id: 3, done: true }
];
const completedTasks = tasks.filter(task => task.done);
console.log("已完成任务:", completedTasks); // [{id:1,...}, {id:3,...}]
练习5:数组判断(someevery
const numbers = [2, 4, 6, 7];// 1. 判断是否有奇数(some)
const hasOdd = numbers.some(num => num % 2 !== 0);
console.log("是否有奇数:", hasOdd); // true(7是奇数)// 2. 判断是否全是偶数(every)
const allEven = numbers.every(num => num % 2 === 0);
console.log("是否全是偶数:", allEven); // false// 3. 判断所有分数是否≥60
const scores = [{ score: 60 }, { score: 80 }, { score: 90 }];
const allPass = scores.every(item => item.score >= 60);
console.log("是否全部及格:", allPass); // true
练习6:数组聚合(reduce
// 1. 求和
const sum = [1, 2, 3, 4, 5].reduce((acc, cur) => acc + cur, 0);
console.log("总和:", sum); // 15// 2. 求平均值
const avg = [1, 2, 3, 4, 5].reduce((acc, cur, _, arr) => {acc += cur;// 最后一次迭代时计算平均值return _ === arr.length - 1 ? acc / arr.length : acc;
}, 0);
console.log("平均值:", avg); // 3// 3. 数组去重
const unique = [1, 2, 2, 3, 3, 3].reduce((acc, cur) => {if (!acc.includes(cur)) acc.push(cur);return acc;
}, []);
console.log("去重结果:", unique); // [1, 2, 3]// 4. 累加count属性
const items = [{ name: 'a', count: 2 },{ name: 'b', count: 3 }
];
const totalCount = items.reduce((acc, item) => acc + item.count, 0);
console.log("总count:", totalCount); // 5
练习7:数组排序(sort
// 1. 升序排序
const arr1 = [3, 1, 4, 2];
arr1.sort((a, b) => a - b);
console.log("升序结果:", arr1); // [1, 2, 3, 4]// 2. 降序排序
const arr2 = [3, 1, 4, 2];
arr2.sort((a, b) => b - a);
console.log("降序结果:", arr2); // [4, 3, 2, 1]// 3. 按age升序排序对象数组
const people = [{ name: '张三', age: 20 },{ name: '李四', age: 18 }
];
people.sort((a, b) => a.age - b.age);
console.log("按年龄排序:", people); // [李四(18), 张三(20)]
练习8:数组扁平化(flatflatMap
// 1. 完全扁平化嵌套数组
const nestedArr = [1, [2, [3, [4]]]];
const flatArr = nestedArr.flat(Infinity); // 无限深度
console.log("完全扁平化:", flatArr); // [1, 2, 3, 4]// 2. flatMap处理字符串数组
const strs = ['hello world', 'good morning'];
const words = strs.flatMap(str => str.split(' '));
console.log("拆分并扁平化:", words); // ['hello','world','good','morning']
练习9:数组查找(indexOffindfindIndex
// 1. indexOf查找元素第一次出现的索引
const nums = [10, 20, 30, 20];
const firstIndex = nums.indexOf(20);
console.log("20第一次出现的索引:", firstIndex); // 1// 2. find查找id=2的对象
const objs = [{ id: 1, name: 'a' },{ id: 2, name: 'b' }
];
const foundObj = objs.find(obj => obj.id === 2);
console.log("找到的对象:", foundObj); // {id:2, name:'b'}// 3. findIndex查找第一个大于12的元素索引
const values = [5, 10, 15, 20];
const targetIndex = values.findIndex(val => val > 12);
console.log("大于12的元素索引:", targetIndex); // 2(元素15)
练习10:综合练习(多方法组合)
const data = [{ name: '张三', score: 85, subject: '数学' },{ name: '张三', score: 90, subject: '语文' },{ name: '李四', score: 75, subject: '数学' },{ name: '李四', score: 80, subject: '语文' }
];// 1. 筛选出数学成绩≥80的记录
const mathPass = data.filter(item => item.subject === '数学' && item.score >= 80);
console.log("数学及格的记录:", mathPass); 
// [{name: '张三', score:85, subject:'数学'}]// 2. 提取所有学生的语文成绩
const chineseScores = data.filter(item => item.subject === '语文').map(item => ({ name: item.name, score: item.score }));
console.log("语文成绩:", chineseScores); 
// [{name: '张三', score:90}, {name: '李四', score:80}]// 3. 计算每个学生的平均分
const avgScores = data// 先按姓名分组.reduce((acc, item) => {const student = acc.find(s => s.name === item.name);if (student) {student.scores.push(item.score);} else {acc.push({ name: item.name, scores: [item.score] });}return acc;}, [])// 再计算平均分.map(student => ({name: student.name,avg: student.scores.reduce((sum, s) => sum + s, 0) / student.scores.length}));
console.log("学生平均分:", avgScores); 
// [{name: '张三', avg:87.5}, {name: '李四', avg:77.5}]

拓展 数组实际应用场景

1. 数据筛选与格式化(电商商品列表处理)

场景:从接口返回的商品列表中,筛选出“在售且价格低于100元”的商品,并格式化展示字段。

// 接口返回的原始数据
const products = [{ id: 1, name: "T恤", price: 89, status: "onSale", category: "服装" },{ id: 2, name: "运动鞋", price: 199, status: "onSale", category: "鞋类" },{ id: 3, name: "袜子", price: 19, status: "onSale", category: "服装" },{ id: 4, name: "背包", price: 299, status: "outOfStock", category: "配饰" },
];// 处理逻辑:筛选 + 格式化
const filteredProducts = products.filter(item => item.status === "onSale" && item.price < 100) // 筛选在售且低价商品.map(item => ({// 只保留需要的字段并格式化productId: item.id,productName: item.name,salePrice: `¥${item.price.toFixed(2)}`, // 价格格式化category: item.category}));console.log(filteredProducts);
// 输出:
// [
//   { productId: 1, productName: "T恤", salePrice: "¥89.00", category: "服装" },
//   { productId: 3, productName: "袜子", salePrice: "¥19.00", category: "服装" }
// ]
2. 数组聚合与统计(用户订单分析)

场景:统计用户订单中各状态的数量,并计算总消费金额。

// 订单数据
const orders = [{ id: 1, userId: 101, amount: 89, status: "paid" },{ id: 2, userId: 101, amount: 159, status: "paid" },{ id: 3, userId: 101, amount: 49, status: "cancelled" },{ id: 4, userId: 101, amount: 299, status: "pending" },
];// 聚合统计:用reduce一次性完成多维度计算
const orderStats = orders.reduce((acc, order) => {// 1. 累计总消费金额(只算已支付)if (order.status === "paid") {acc.totalPaid += order.amount;}// 2. 统计各状态数量if (acc.statusCount[order.status]) {acc.statusCount[order.status]++;} else {acc.statusCount[order.status] = 1;}return acc;},{ totalPaid: 0, statusCount: {} } // 初始值
);console.log(orderStats);
// 输出:
// {
//   totalPaid: 248, // 89 + 159
//   statusCount: { paid: 2, cancelled: 1, pending: 1 }
// }
3. 数组去重与合并(用户标签管理)

场景:合并两个用户标签数组,并去除重复标签,同时按字母排序。

// 已有标签和新标签
const existingTags = ["前端", "JavaScript", "React"];
const newTags = ["React", "Vue", "前端", "TypeScript"];// 合并、去重、排序
const uniqueTags = [...new Set([...existingTags, ...newTags])] // 合并+去重.sort((a, b) => a.localeCompare(b)); // 按中文拼音排序console.log(uniqueTags);
// 输出:["JavaScript", "React", "TypeScript", "Vue", "前端"]
4. 嵌套数组处理(多级评论数据扁平化)

场景:将嵌套的评论数据(含子评论)扁平化为一维数组,方便渲染。

// 嵌套评论数据
const comments = [{id: 1,content: "主评论1",replies: [{ id: 11, content: "子评论1-1" },{ id: 12, content: "子评论1-2" }]},{id: 2,content: "主评论2",replies: []}
];// 扁平化:用reduce递归处理嵌套结构
const flattenComments = comments.reduce((acc, comment) => {// 先推入当前主评论acc.push({ id: comment.id, content: comment.content, isReply: false });// 再处理子评论(递归)if (comment.replies.length > 0) {const replyComments = comment.replies.map(reply => ({...reply,isReply: true}));acc.push(...flattenComments(replyComments)); // 递归扁平化}return acc;
}, []);console.log(flattenComments);
// 输出:
// [
//   { id: 1, content: "主评论1", isReply: false },
//   { id: 11, content: "子评论1-1", isReply: true },
//   { id: 12, content: "子评论1-2", isReply: true },
//   { id: 2, content: "主评论2", isReply: false }
// ]
5. 条件查询与分组(学生成绩管理)

场景:将学生成绩按科目分组,并筛选出每科平均分≥80的科目。

// 学生成绩数据
const scores = [{ subject: "数学", name: "张三", score: 85 },{ subject: "数学", name: "李四", score: 92 },{ subject: "语文", name: "张三", score: 78 },{ subject: "语文", name: "李四", score: 88 },{ subject: "英语", name: "张三", score: 90 },{ subject: "英语", name: "李四", score: 85 },
];// 按科目分组并计算平均分
const subjectGroups = scores.reduce((acc, item) => {// 按科目分组if (!acc[item.subject]) {acc[item.subject] = [];}acc[item.subject].push(item.score);return acc;
}, {});// 筛选出平均分≥80的科目
const qualifiedSubjects = Object.entries(subjectGroups).map(([subject, scores]) => {const avg = scores.reduce((sum, s) => sum + s, 0) / scores.length;return { subject, avg: avg.toFixed(1) };}).filter(item => item.avg >= 80);console.log(qualifiedSubjects);
// 输出:
// [
//   { subject: "数学", avg: "88.5" },
//   { subject: "英语", avg: "87.5" }
// ]
6. 数组操作防抖(搜索联想优化)

场景:用户输入搜索关键词时,防抖处理并过滤匹配的选项。

// 所有可选关键词
const allKeywords = ["JavaScript", "Java", "Python", "TypeScript", "PHP"];// 防抖函数(复用之前的实现)
function debounce(fn, delay = 300) {let timer;return (...args) => {clearTimeout(timer);timer = setTimeout(() => fn.apply(this, args), delay);};
}// 搜索输入处理
const searchInput = document.getElementById("searchInput");
searchInput.addEventListener("input",debounce((e) => {const keyword = e.target.value.trim().toLowerCase();if (!keyword) {console.log("请输入关键词");return;}// 筛选匹配的关键词(不区分大小写)const matched = allKeywords.filter(item => item.toLowerCase().includes(keyword));console.log("匹配结果:", matched);})
);
总结

实际项目中,数组方法的价值体现在:

  1. 链式调用filter+map+sort 等组合,高效处理数据流水线。
  2. 聚合能力reduce 几乎能完成所有复杂聚合(分组、统计、转换等)。
  3. 简洁性:替代冗长的 for 循环,代码可读性更高。

根据具体场景选择合适的方法组合,能显著提升开发效率。例如:

  • 筛选数据用 filter,转换数据用 map,两者常链式使用。
  • 复杂统计用 reduce,分组操作是其典型应用。
  • 处理嵌套结构时,flat(浅嵌套)或递归+reduce(深嵌套)更高效。

http://www.xdnf.cn/news/1201231.html

相关文章:

  • JavaScript核心概念全解析
  • 创建属于自己的github Page主页
  • 【Python系列】Flask 应用中的主动垃圾回收
  • 安装redis
  • 生成式召回-TIGER范式
  • Vim 编辑器工作模式及操作指南
  • 抗辐照芯片在低轨卫星星座CAN总线通讯及供电系统的应用探讨
  • 比特币运行机制全解析:区块链、共识算法与数字黄金的未来挑战
  • rapidocr v3.3.0发布了
  • OpenLayers 综合案例-轨迹回放
  • Torchv Unstrustured 文档解析库
  • C语言:函数
  • C/C++核心知识点详解
  • Qt C++ GUI 函数参数速查手册:基础与布局
  • RK3568 Linux驱动学习——Linux驱动开发准备工作
  • 【科研绘图系列】R语言绘制边际云雨图散点图
  • 基于大模型的预训练、量化、微调等完整流程解析
  • rust-模块树中引用项的路径
  • 1439-素数环2
  • 扩展组件(uni-ui)之uni-group
  • 硅基计划3.0 学习总结 肆 二叉树 初版
  • 疯狂星期四文案网第21天运营日记
  • 剑指offer第2版:双指针+排序+分治+滑动窗口
  • QT6 源,七章对话框与多窗体(17)用于辅助多文档 MDI 窗体设计 QMdiArea 的类 QMdiSubWindow:
  • MySQL 8.4 Windows 版安装记录与步骤参考
  • 《频率之光:群星之我》
  • mmap的调用层级与内核态陷入全过程
  • 依赖倒置原则 Dependency Inversion Principle - DIP
  • 不坑盒子突然不见了怎么办?
  • VILA系列论文解读