导读:本期聚焦于小伙伴创作的《JS实现嵌套数组扁平化为键值对:递归与栈迭代方案详解》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《JS实现嵌套数组扁平化为键值对:递归与栈迭代方案详解》有用,将其分享出去将是对创作者最好的鼓励。

JS实现嵌套数组数据扁平化为目标键值对格式

在前端数据处理场景中,我们经常会遇到嵌套数组结构的数据,需要将其扁平化后转换为特定格式的键值对。比如后台返回的树形菜单数据、多级分类数据等,往往需要将嵌套结构拆解为扁平的键值对,方便后续进行数据查询、状态管理或者渲染操作。本文将结合具体示例,讲解几种常用的实现方案。

示例场景说明

假设我们有以下嵌套数组数据,每个数组元素包含id、name字段,以及可能存在的children子数组:

const nestedData = [
  {
    id: 1,
    name: '水果',
    children: [
      { id: 11, name: '苹果' },
      { id: 12, name: '香蕉', children: [{ id: 121, name: '芭蕉' }] }
    ]
  },
  {
    id: 2,
    name: '蔬菜',
    children: [
      { id: 21, name: '白菜' },
      { id: 22, name: '萝卜' }
  }
];

我们的目标是将上述嵌套数组转换为如下键值对格式,其中键为元素的id,值为元素的name:

const targetResult = {
  1: '水果',
  11: '苹果',
  12: '香蕉',
  121: '芭蕉',
  2: '蔬菜',
  21: '白菜',
  22: '萝卜'
};

方案一:递归遍历实现

递归是处理嵌套结构最直观的思路,我们可以编写一个递归函数,遍历数组的每个元素,将当前元素的id和name存入结果对象,若存在children子数组则继续递归处理子数组。

function flattenToKeyValue(arr, result = {}) {
  arr.forEach(item => {
    // 存储当前元素的键值对
    result[item.id] = item.name;
    // 若存在children子数组,递归处理
    if (item.children && Array.isArray(item.children)) {
      flattenToKeyValue(item.children, result);
    }
  });
  return result;
}

// 调用函数
const result1 = flattenToKeyValue(nestedData);
console.log(result1);
// 输出结果与targetResult一致

该方案的逻辑清晰,适合嵌套层级不固定的场景,时间复杂度为O(n),n为所有元素的总个数。需要注意的是,如果数据源中存在重复的id,后遍历到的元素会覆盖之前存储的同键名值。

方案二:栈迭代实现

递归虽然直观,但如果嵌套层级过深可能导致栈溢出,此时可以使用栈的迭代方式实现,避免递归调用带来的栈溢出风险。

function flattenToKeyValueByStack(arr) {
  const result = {};
  // 初始化栈,将初始数组的所有元素入栈
  const stack = [...arr];
  while (stack.length > 0) {
    const current = stack.pop();
    // 存储当前元素的键值对
    result[current.id] = current.name;
    // 若存在children子数组,将子数组元素入栈
    if (current.children && Array.isArray(current.children)) {
      stack.push(...current.children);
    }
  }
  return result;
}

// 调用函数
const result2 = flattenToKeyValueByStack(nestedData);
console.log(result2);
// 输出结果与targetResult一致

该方案通过栈模拟递归的遍历过程,同样可以处理任意层级的嵌套数组,且没有递归深度限制,适合处理层级特别深的数据场景。

方案三:支持自定义键名的通用版本

如果实际场景中需要自定义的键和值对应的字段名,比如键不一定用id,值不一定用name,我们可以给函数增加配置参数,让方法更通用。

function flattenToCustomKeyValue(arr, keyField = 'id', valueField = 'name', result = {}) {
  arr.forEach(item => {
    // 使用传入的字段名获取键和值
    result[item[keyField]] = item[valueField];
    if (item.children && Array.isArray(item.children)) {
      flattenToCustomKeyValue(item.children, keyField, valueField, result);
    }
  });
  return result;
}

// 调用示例:假设键用code字段,值用label字段
const customData = [
  {
    code: 'A',
    label: '一级分类',
    children: [{ code: 'A1', label: '二级分类' }]
  }
];
const customResult = flattenToCustomKeyValue(customData, 'code', 'label');
console.log(customResult);
// 输出:{ A: '一级分类', A1: '二级分类' }

注意事项

  • 处理数据前建议先判断输入是否为合法数组,避免非数组入参导致的报错,可添加类型校验逻辑。

  • 如果数据源中可能存在循环引用(比如children引用了父级对象),递归或栈遍历都会陷入死循环,需要额外添加已访问元素缓存来处理这种情况。

  • 若需要保留原始元素的所有字段,也可以将值设置为整个元素对象,只需要调整赋值逻辑为result[item.id] = item即可。

JavaScript 数组扁平化 键值对转换 递归算法 栈迭代

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。