前端面经整理【1】

注:纯手打,如有错误欢迎评论区交流!

转载请注明出处:https://blog.csdn.net/testleaf/article/details/148628299

编写此文是为了更好地学习前端知识,如果损害了有关人的利益,请联系删除!

本文章将不定时更新,敬请期待!!!

欢迎点赞、收藏、转发、关注,多谢!!!

目录

【1】数组转树

数组转树是前端面试中的高频手写题,通常用于处理扁平化的数据结构(如菜单列表、评论嵌套等)。

输入示例​​:

javascript 复制代码
const arr = [
  { id: 1, name: '部门A', parentId: 0 },
  { id: 4, name: '部门D', parentId: 2 },
  { id: 2, name: '部门B', parentId: 1 },
  { id: 3, name: '部门C', parentId: 1 },
];

输出示例:

javascript 复制代码
[
  {
    id: 1,
    name: '部门A',
    children: [
      { 
        id: 2, 
        name: '部门B',
        children: [{ id: 4, name: '部门D', children: [] }]
      },
      { id: 3, name: '部门C', children: [] }
    ]
  }
]

实现方法1【递归法(O(n²))​】:

javascript 复制代码
// 原始数据:扁平化的部门列表,每个部门有 id、name 和 parentId
const arr = [
  { id: 1, name: '部门A', parentId: 0 },  // 根节点(parentId=0)
  { id: 4, name: '部门D', parentId: 2 },  // 部门D 的父节点是部门B(id=2)
  { id: 2, name: '部门B', parentId: 1 },  // 部门B 的父节点是部门A(id=1)
  { id: 3, name: '部门C', parentId: 1 },  // 部门C 的父节点是部门A(id=1)
];
/**
 * 将扁平数组转换为树形结构
 * @param {Array} items - 扁平数组
 * @param {number} parentId - 当前层级的父节点ID(默认0表示根节点)
 * @returns {Array} - 树形结构数组
 */
const change = (items, parentId = 0) => {
  let result = []; // 当前层级的节点数组
  // 遍历所有部门,找出属于当前 parentId 的子部门
  items.forEach(item => {
    if (item.parentId == parentId) {
      // 递归查找当前部门的子部门(以当前部门的 id 作为父ID)
      item.children = change(items, item.id);
      // 删除 parentId 字段(可选,树形结构不再需要该字段)
      delete item.parentId;
      // 将当前部门添加到结果中
      result.push(item);
    }
  });
  return result; // 返回当前层级的部门树
};
// 打印完整的树形结构({depth:null} 表示展开所有层级)
console.dir(change(arr), { depth: null });

实现方法2【哈希表 + 一次遍历(O(n))​​】:

javascript 复制代码
// 原始数据:扁平化的部门列表,每个部门有 id、name 和 parentId
const arr = [
  { id: 1, name: '部门A', parentId: 0 },  // 根节点(parentId=0)
  { id: 4, name: '部门D', parentId: 2 },  // 部门D 的父节点是部门B(id=2)
  { id: 2, name: '部门B', parentId: 1 },  // 部门B 的父节点是部门A(id=1)
  { id: 3, name: '部门C', parentId: 1 },  // 部门C 的父节点是部门A(id=1)
];
/**
 * 使用哈希表将扁平数组转换为树形结构(O(n) 时间复杂度)
 * @param {Array} items - 扁平数组
 * @returns {Array} - 树形结构数组
 */
const change = (items) => {
  // 1. 初始化哈希表:存储所有节点的引用,方便后续通过 id 快速查找
  const map = {};
  // 2. 结果数组:存储所有根节点(parentId=0 的节点)
  const result = [];
  // 第一次遍历:将所有节点存入哈希表,并初始化 children 数组
  for (const item of items) {
    map[item.id] = {
      ...item,          // 浅拷贝原对象(避免直接修改原数据)
      children: []      // 初始化子节点数组
    };
  }
  // 第二次遍历:构建树形结构
  for (const item of items) {
    // 获取当前节点在哈希表中的引用
    const node = map[item.id];
    if (item.parentId === 0) {
      // 如果是根节点(parentId=0),直接加入结果数组
      delete node.parentId;  // 可选:删除冗余的 parentId 字段
      result.push(node);
    } else {
      // 如果不是根节点,找到父节点并挂载到父节点的 children 中
      if (map[item.parentId]) {
        delete node.parentId;  // 可选:删除冗余的 parentId 字段
        map[item.parentId].children.push(node);
      }
      // 注:如果父节点不存在(数据错误),这里会静默忽略,实际业务中可以报警告
    }
  }
  return result;
};
// 打印完整的树形结构({depth:null} 表示展开所有嵌套层级)
console.dir(change(arr), { depth: null });

思考:

为什么 map[item.parentId].children.push(node) 会影响所有相关节点?

  • JavaScript 的对象是引用类型
    • map[item.id] = {...item, children: []} 创建的是 浅拷贝(只拷贝第一层属性)。
    • map 中存储的是对节点的引用,nodemap[item.id] 指向同一个对象。
  • ​​children 数组的共享
    • 当执行 map[item.parentId].children.push(node) 时:
      • map[item.parentId] 是父节点的引用。
      • node 是子节点的引用。
      • 父子节点通过引用关联,修改会同步反映到所有引用该对象的地方。
相关推荐
小白变怪兽8 分钟前
一、react18+项目初始化(vite)
前端·react.js
ai小鬼头11 分钟前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
墨菲安全1 小时前
NPM组件 betsson 等窃取主机敏感信息
前端·npm·node.js·软件供应链安全·主机信息窃取·npm组件投毒
GISer_Jing1 小时前
Monorepo+Pnpm+Turborepo
前端·javascript·ecmascript
天涯学馆1 小时前
前端开发也能用 WebAssembly?这些场景超实用!
前端·javascript·面试
我在北京coding2 小时前
TypeError: Cannot read properties of undefined (reading ‘queryComponents‘)
前端·javascript·vue.js
前端开发与ui设计的老司机3 小时前
UI前端与数字孪生结合实践探索:智慧物流的货物追踪与配送优化
前端·ui
全能打工人3 小时前
前端查询条件加密传输方案(SM2加解密)
前端·sm2前端加密
翻滚吧键盘3 小时前
vue绑定一个返回对象的计算属性
前端·javascript·vue.js
秃了也弱了。4 小时前
Chrome谷歌浏览器插件ModHeader,修改请求头,开发神器
前端·chrome