JavaScript 数组核心操作实战:最值获取与排序实现(从基础到优化)
在JavaScript开发中,数组的“最值获取”和“排序”是高频需求。本文将基于你的原始代码,系统解析数组最值获取、升序/降序排序的实现逻辑,通过“问题分析→代码优化→原理讲解”的流程,帮助你掌握更灵活、高效的数组操作方法,同时避免重复编码。
一、需求1:创建函数获取数组中的最大值和最小值
你的代码中已实现了排序功能,但尚未单独封装“最值获取”逻辑。我们先从“如何高效获取数组最值”入手,对比基础实现与优化方案。
1. 原始思路:基于排序的最值获取(间接方法)
你的排序函数(如maxMin降序排序、minMax升序排序)其实可以间接获取最值——降序排序后数组第1个元素是最大值,升序排序后第1个元素是最小值。但这种方式存在性能浪费(排序的时间复杂度高于直接遍历)。
间接获取示例(基于你的排序函数):
<script>
// 基于已有排序函数间接获取最值(不推荐,性能差)
function getMinMaxBySort(arr) {
// 复制数组(避免修改原数组)
const sortedArr = [...arr];
// 降序排序(复用你的冒泡排序逻辑)
for(let i=0; i<sortedArr.length; i++){
for(let j=i; j<sortedArr.length; j++){
if(sortedArr[i] < sortedArr[j]){
const temp = sortedArr[j];
sortedArr[j] = sortedArr[i];
sortedArr[i] = temp;
}
}
}
// 间接获取最值:第1个是最大值,最后1个是最小值
return {
max: sortedArr[0],
min: sortedArr[sortedArr.length - 1]
};
}
// 测试
const testArr = [77, 55, 88, 22, 666, 0];
const { max, min } = getMinMaxBySort(testArr);
console.log("最大值:", max); // 666
console.log("最小值:", min); // 0
</script>
问题分析:
- 性能浪费:排序需要双重循环(时间复杂度O(n²)),而直接遍历只需一次循环(O(n)),数据量大时效率差距明显;
- 逻辑冗余:为了获取2个值,却要对整个数组排序,属于“过度操作”。
2. 优化方案:直接遍历获取最值(高效方法)
核心思路:假设数组第1个元素为初始最值,然后遍历数组逐一对比,更新最值。这种方式只需一次循环,性能更优,且逻辑更直接。
优化后完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>数组最值获取(优化版)</title>
<style>
.result {
margin: 20px;
padding: 15px;
border: 1px solid #eee;
border-radius: 6px;
font-size: 16px;
}
</style>
</head>
<body>
<div class="result" id="result"></div>
<script>
window.onload = function() {
// 测试数组(可替换为任意数字数组)
const arr = [77, 55, 88, 22, 55, 88, 666, 55, 22, 0];
// 调用最值获取函数
const { max, min } = getArrayMinMax(arr);
// 渲染结果
const resultDiv = document.getElementById("result");
resultDiv.innerHTML = `
原始数组:${arr.join(", ")}<br>
数组最大值:<strong>${max}</strong><br>
数组最小值:<strong>${min}</strong>
`;
};
/**
* 封装函数:直接遍历获取数组的最大值和最小值
* @param {Array} arr - 待处理的数字数组(必须是纯数字数组)
* @returns {Object} - 包含max(最大值)和min(最小值)的对象
*/
function getArrayMinMax(arr) {
// 边界判断:若数组为空,返回null(避免报错)
if (arr.length === 0) {
console.error("数组不能为空!");
return { max: null, min: null };
}
// 初始值:假设数组第1个元素为最值(避免重复对比)
let max = arr[0];
let min = arr[0];
// 遍历数组:从第2个元素开始对比(i从1开始,减少1次循环)
for (let i = 1; i < arr.length; i++) {
const current = arr[i];
// 对比最大值:若当前元素大于max,更新max
if (current > max) {
max = current;
}
// 对比最小值:若当前元素小于min,更新min
if (current < min) {
min = current;
}
}
// 返回结果
return { max, min };
}
</script>
</body>
</html>
优化点说明
- 性能优化:时间复杂度从O(n²)降至O(n),数据量越大优势越明显;
- 边界处理:新增“数组为空”的判断,避免后续代码报错;
- 遍历优化:从第2个元素(i=1)开始遍历,减少1次无效对比;
- 通用性:通过参数
arr接收任意数字数组,不再固定数组内容,可复用至任何场景; - 清晰返回:返回包含
max和min的对象,便于解构赋值使用。
二、需求2:创建函数对数组进行排序(升序/降序)
你的原始代码已实现了升序(minMax)和降序(maxMin)排序,但存在代码重复问题(两个函数逻辑几乎一致,仅判断条件不同)。我们通过“参数控制排序方向”优化,将两个函数合并为一个,减少冗余。
1. 原始代码分析:重复问题
你的两个排序函数maxMin(降序)和minMax(升序)的核心逻辑对比:
| 函数名 | 排序方向 | 核心判断条件 | 问题 |
|---|---|---|---|
maxMin | 降序 | if(arr[i] < arr[j])(交换元素,让大的在前) | 代码重复,仅判断条件不同 |
minMax | 升序 | if(arr[i] > arr[j])(交换元素,让小的在前) | 新增排序方向需写新函数,扩展性差 |
2. 优化方案:参数控制排序方向(合并函数)
核心思路:用一个参数(如sortType)控制排序方向(asc升序、desc降序),通过条件判断动态切换对比逻辑,将两个函数合并为一个通用排序函数。
优化后完整代码(冒泡排序实现)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>数组排序(优化版:支持升序/降序)</title>
<style>
.container {
margin: 20px;
max-width: 600px;
}
.btn-group {
margin-bottom: 15px;
}
.btn {
padding: 8px 16px;
margin-right: 10px;
border: none;
border-radius: 4px;
background-color: #4096ff;
color: #fff;
cursor: pointer;
}
.btn:hover {
background-color: #3086e8;
}
.result {
padding: 15px;
border: 1px solid #eee;
border-radius: 6px;
background-color: #f8f9fa;
}
</style>
</head>
<body>
<div class="container">
<div class="btn-group">
<button class="btn" onclick="sortArray('asc')">升序排序(从小到大)</button>
<button class="btn" onclick="sortArray('desc')">降序排序(从大到小)</button>
</div>
<div class="result" id="sortResult"></div>
</div>
<script>
// 原始数组(固定,每次排序基于原始数组,避免修改原数组)
const originalArr = [77, 55, 88, 22, 55, 88, 666, 55, 22, 0];
// 页面加载时显示原始数组
window.onload = function() {
const resultDiv = document.getElementById("sortResult");
resultDiv.innerHTML = `原始数组:${originalArr.join(", ")}`;
};
/**
* 通用排序函数:支持升序和降序(基于冒泡排序)
* @param {string} sortType - 排序方向:'asc'(升序,默认)、'desc'(降序)
*/
function sortArray(sortType = 'asc') {
// 复制原始数组(关键:避免修改原数组,每次排序都是基于原始数据)
const arr = [...originalArr];
const len = arr.length;
// 冒泡排序核心逻辑(双重循环)
for (let i = 0; i < len; i++) {
// 内层循环:每轮将最大/最小值“冒泡”到对应位置
for (let j = i; j < len; j++) {
// 动态判断是否需要交换:根据sortType切换对比逻辑
const needSwap = sortType === 'asc'
? arr[i] > arr[j] // 升序:前大后小则交换(让小的在前)
: arr[i] < arr[j]; // 降序:前小后大则交换(让大的在前)
// 交换元素(ES6解构赋值,更简洁)
if (needSwap) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
}
// 渲染排序结果
const resultDiv = document.getElementById("sortResult");
const directionText = sortType === 'asc' ? "从小到大" : "从大到小";
resultDiv.innerHTML = `
原始数组:${originalArr.join(", ")}<br>
${directionText}排序后:<strong>${arr.join(", ")}</strong>
`;
}
</script>
</body>
</html>
优化点说明
- 合并函数:用
sortType参数控制排序方向,将两个函数合并为一个,减少50%重复代码; - 保护原数组:通过
[...originalArr]复制数组,每次排序基于副本,避免原始数据被修改; - 默认值处理:
sortType = 'asc'设置默认排序为升序,调用时可省略参数; - 简洁交换:用ES6解构赋值
[arr[i], arr[j]] = [arr[j], arr[i]]替代临时变量,代码更简洁; - 用户体验:添加按钮交互,实时切换排序方向,展示原始数组与排序结果对比。
3. 进阶:使用JS内置sort()方法(更高效)
除了手动实现冒泡排序,JavaScript数组内置了sort()方法,可快速实现排序。但需注意:sort()默认按“字符串Unicode码”排序,对数字排序需传入“比较函数”。
内置sort()方法实现(简化版)
<script>
// 原始数组
const arr = [77, 55, 88, 22, 666, 0];
// 1. 升序排序(从小到大)
const ascSorted = [...arr].sort((a, b) => a - b);
console.log("升序:", ascSorted); // [0, 22, 22, 55, 55, 55, 77, 88, 88, 666]
// 2. 降序排序(从大到小)
const descSorted = [...arr].sort((a, b) => b - a);
console.log("降序:", descSorted); // [666, 88, 88, 77, 55, 55, 55, 22, 22, 0]
// 对比:默认排序(错误,按字符串排序)
const wrongSorted = [...arr].sort();
console.log("默认排序(错误):", wrongSorted); // [0, 22, 22, 55, 55, 55, 666, 77, 88, 88]
</script>
内置方法优势
- 代码极简:无需手动写双重循环,一行代码实现排序;
- 性能更优:
sort()底层实现(如V8引擎用快速排序+插入排序)比手动冒泡排序(O(n²))效率更高(时间复杂度O(n log n)); - 通用性强:支持自定义排序规则(如对象数组按某属性排序)。
三、综合案例:数组最值+排序整合展示
将“最值获取”和“排序”功能整合,实现一个完整的数组操作演示页面,展示两种功能的联动。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>数组操作综合演示(最值+排序)</title>
<style>
.container {
margin: 20px auto;
max-width: 700px;
padding: 20px;
border: 1px solid #eee;
border-radius: 8px;
}
.title {
text-align: center;
color: #333;
margin-bottom: 20px;
}
.btn {
padding: 8px 16px;
margin: 0 5px;
border: none;
border-radius: 4px;
cursor: pointer;
background-color: #4096ff;
color: #fff;
}
.btn:hover {
background-color: #3086e8;
}
.info {
margin: 15px 0;
padding: 15px;
background-color: #f8f9fa;
border-radius: 6px;
}
.highlight {
color: #e74c3c;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h2 class="title">数组操作综合演示</h2>
<div style="text-align: center; margin-bottom: 20px;">
<button class="btn" onclick="showMinMax()">获取数组最值</button>
<button class="btn" onclick="sortArray('asc')">升序排序</button>
<button class="btn" onclick="sortArray('desc')">降序排序</button>
</div>
<div class="info">
<p>原始数组:<span id="originalArr">[77, 55, 88, 22, 55, 88, 666, 55, 22, 0]</span></p>
<p>数组最值:<span id="minMaxInfo">未计算</span></p>
<p>排序结果:<span id="sortInfo">未排序</span></p>
</div>
</div>
<script>
// 原始数组
const originalArr = [77, 55, 88, 22, 55, 88, 666, 55, 22, 0];
// 1. 获取数组最值
function showMinMax() {
const { max, min } = getArrayMinMax(originalArr);
const minMaxElem = document.getElementById("minMaxInfo");
minMaxElem.innerHTML = `最大值:<span class="highlight">${max}</span>,最小值:<span class="highlight">${min}</span>`;
}
// 2. 数组排序(升序/降序)
function sortArray(sortType) {
const sortedArr = [...originalArr].sort((a, b) => sortType === 'asc' ? a - b : b - a);
const sortElem = document.getElementById("sortInfo");
const direction = sortType === 'asc' ? "升序(从小到大)" : "降序(从大到小)";
sortElem.innerHTML = `${direction}:<span class="highlight">${sortedArr.join(", ")}</span>`;
}
// 3. 复用之前的最值获取函数
function getArrayMinMax(arr) {
if (arr.length === 0) return { max: null, min: null };
let max = arr[0], min = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
return { max, min };
}
</script>
</body>
</html>
四、核心知识点总结
1. 数组最值获取
- 推荐方法:直接遍历(O(n)),避免基于排序的间接获取(O(n²));
- 关键步骤:
- 初始值设为数组第1个元素;
- 遍历数组逐一对比,更新max和min;
- 处理空数组边界情况。
2. 数组排序
| 排序方式 | 实现方式 | 时间复杂度 | 适用场景 |
|---|---|---|---|
| 手动冒泡排序 | 双重循环,逐轮交换元素 | O(n²) | 学习排序原理,小规模数据 |
内置sort()方法 | 传入比较函数(a-b升序) | O(n log n) | 实际开发,高效简洁 |
- 注意事项:
sort()默认按字符串排序,数字排序必须传比较函数((a,b)=>a-b升序,(a,b)=>b-a降序)。
3. 代码优化原则
- 避免重复:用参数控制差异逻辑(如排序方向),合并重复函数;
- 保护原数据:通过数组复制(
[...arr])避免修改原始数组; - 边界处理:新增空数组、非数字数组的判断,提升函数健壮性;
- 易用性:函数返回清晰结构(如包含max/min的对象),便于调用者使用。
最终结论
你的原始代码已掌握了数组排序的核心逻辑(冒泡排序),通过优化后:
- 最值获取从“间接排序”改为“直接遍历”,性能提升;
- 排序函数从“两个分离”合并为“一个通用”,减少重复代码;
- 引入内置
sort()方法,兼顾学习原理与实际开发效率。
在后续开发中,建议优先使用内置方法(如sort()、Math.max(...arr))提升效率,同时理解手动实现的原理(如冒泡排序),这样既能应对面试中的原理考察,也能在需要自定义排序规则时灵活扩展。
更多推荐


所有评论(0)