
本文详解如何在 javascript 中对含嵌套结构的混合类型数据(如 course/chapter/lesson)进行稳定、可扩展的多级排序,兼顾类型优先级与关联字段(如 course.sequence、chapter.sequence)的层级化排序逻辑。
本文详解如何在 javascript 中对含嵌套结构的混合类型数据(如 course/chapter/lesson)进行稳定、可扩展的多级排序,兼顾类型优先级与关联字段(如 course.sequence、chapter.sequence)的层级化排序逻辑。
在实际前端开发中,常需对具有层级关系的异构数据(如课程体系中的 course → chapter → lesson)进行统一排序。这类数据不仅需按类型(type)设定严格优先级(course > chapter > lesson),还需在同类项内依据其所属上级的 sequence 及自身的 sequence 进行递进排序。直接按 type 字符串排序不可靠(如 "chapter" 字典序小于 "course"),而拆分-合并数组又破坏代码简洁性与可维护性。理想方案是使用一个语义清晰、可扩展、纯函数式的 Array.prototype.sort() 比较器。
核心思路是:将排序维度建模为“层级粒度”与“序列值”的双重判断。
- 层级粒度由对象是否包含 course、chapter 等关键嵌套属性决定:course 级(无父级)粒度最粗,lesson 级(含 course 且含 chapter)粒度最细;
- 比较时先比粒度:粒度粗者(如仅有 course)排在前面;
- 粒度相同时再比序列:依次比较 course.sequence → chapter.sequence → 自身 sequence,任一不等即终止比较。
以下是生产就绪的排序实现:
const sortedIds = data.sort((a, b) => {
// Step 1: 按层级粒度排序 —— 粒度越粗(嵌套越少)优先级越高
const aHasCourse = 'course' in a;
const bHasCourse = 'course' in b;
const aHasChapter = 'chapter' in a;
const bHasChapter = 'chapter' in b;
// 优先:无 course 的排最前(course 类型)
if (!aHasCourse && bHasCourse) return -1;
if (aHasCourse && !bHasCourse) return 1;
// 其次:有 course 但无 chapter 的排在有 chapter 之前(chapter 类型)
if (aHasCourse && !aHasChapter && bHasCourse && bHasChapter) return -1;
if (aHasCourse && aHasChapter && bHasCourse && !bHasChapter) return 1;
// Step 2: 粒度相同时,逐级比较 sequence
// 先比 course.sequence(若存在)
if (aHasCourse && bHasCourse) {
if (a.course.sequence !== b.course.sequence) {
return a.course.sequence - b.course.sequence;
}
}
// 再比 chapter.sequence(若都存在 chapter)
if (aHasChapter && bHasChapter) {
if (a.chapter.sequence !== b.chapter.sequence) {
return a.chapter.sequence - b.chapter.sequence;
}
}
// 最后比自身 sequence
return a.sequence - b.sequence;
}).map(item => item.id);✅ 优势说明:
立即学习“Java免费学习笔记(深入)”;
- 健壮性:显式检查属性存在性('course' in a),避免 undefined?.sequence 报错;
- 可读性:逻辑分层清晰(粒度判定 → 序列比较),便于后续扩展(如新增 section 类型);
- 稳定性:所有比较分支均返回 -1/0/1,确保 sort() 稳定性(ES2019+ 环境下);
- 零依赖:纯原生 JavaScript,无需外部库。
⚠️ 注意事项:
- 若数据中存在 type 字段需参与排序(如题干强调 “course > chapter > lesson”),可在粒度判定后补充 type 映射权重(例如 const typeOrder = { course: 0, chapter: 1, lesson: 2 };),并在粒度相同时作为首级比较项;
- 对于超大规模数据(>10k 条),建议预先计算并缓存排序键(如生成 sortKey: "001-001-001" 字符串),以提升性能;
- 始终对原始数组使用 slice().sort() 或 [...data].sort(),避免意外修改源数据。
通过该模式,你不仅能精准复现题干所需的 course1, course2, course1_chapter1, ... 排序结果,更能构建出可随业务演进灵活调整的通用层级排序能力。










