前端面试手撕代码(字节)

前端面试手撕代码(字节)

字节一面给了两道手撕代码,还是比较偏向场景,不是leetcode那种逻辑题。

题目一:实现 Compile 函数

这是一道经典的前端面试题,一般面试中如果你提到框架原理,面试官都会想到这道题。 之前拼多多面试也考了,但是比这个复杂,要求还要渲染对象中的数组juejin.cn/post/747562...

题目要求

将模板字符串中的插值(如 {{user.name}})编译为具体的值。例如,输入模板 "Hello, {{user.name}}!" 和数据 {user: {name: "Alice"}},输出 "Hello, Alice!"

实现思路
  1. 正则匹配插值 :使用正则表达式(如 /\{\{([^}]+)\}\}/g)定位模板中的插值表达式,提取变量路径(如 user.name)。
  2. 数据路径解析 :将变量路径按 . 分割为层级数组(如 ["user", "name"]),逐层访问数据对象的属性。

代码示例

javascript 复制代码
function compile(template) {
  const regex = /\{\{([^}]+)\}\}/g;
  return function(data) {
    return template.replace(regex, (match, path) => {
      const keys = path.trim().split('.');
      return keys.reduce((obj, key) => obj?.[key], data) || '';
    });
  };
}

// 使用示例
const template = "Hello, {{user.name}}! Age: {{age}}";
const render = compile(template);
console.log(render({ user: { name: "Alice" }, age: 25 })); 
// 输出: "Hello, Alice! Age: 25"

优化点

缓存正则表达式 :避免重复创建正则对象提升性能。

处理深层嵌套 :通过 reduce 逐层安全访问属性,避免因路径错误导致的报错。

法二:使用with函数实现
javascript 复制代码
function compile(template, context) {
  // 替换模板中的插值表达式为 JavaScript 模板字符串语法
  const compiledTemplate = template.replace(
    /{{(.*?)}}/g,
    (match, p1) => `\${${p1.trim()}}`
  );

  // 动态生成一个函数,用于替换模板中的插值表达式
  const compiledFunction = new Function(
    "context",
    `
    with (context) {
      return \`${compiledTemplate}\`;
    }
  `
  );

  // 调用函数并返回结果
  return compiledFunction(context);
}



const template =
  "Hello, ${user.name}! Your balance is${user.balance}. You have ${user.items[0]} in your cart. and${user.items[2].kk}";
const exprObj = {
  user: {
    name: "Alice",
    balance: 100.5,
    items: ["Item1", "Item2", { kk: 1 }],
  },
};
const compiledString = compile(template, exprObj);
console.log(compiledString);

使用with函数是非常取巧的,不仅代码少,而且处理了所有情况,面试如果想要快速实现,可以使用第法二。


题目二:树形菜单渲染

题目要求

给定树形结构数据,将其渲染为 HTML 菜单,并支持点击展开/收起子节点。例如输入:

javascript 复制代码
const treeData = [
  {
    "id": 1,
    "parent_id": 0,
    "name": "北京",
    "children": [
      {
        "id": 3,
        "parent_id": 1,
        "name": "海淀区",
        "children": []
      },
      {
        "id": 4,
        "parent_id": 1,
        "name": "朝阳区",
        "children": []
      }
    ]
  }
];

输出可交互的树形菜单,点击父节点时切换子节点的显示状态。


完整实现方案

以下代码通过 DOM 操作事件绑定实现动态渲染与交互:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Tree Directory Component</title>
  <style>
    .tree-node { cursor: pointer; margin-left: 20px; }
    .children { display: none; margin-left: 20px; } /* 默认隐藏子节点 */
  </style>
</head>
<body>
  <div id="tree"></div>
  <script>
    const treeData = [/* 此处省略,结构与上文一致 */];

    // 递归创建树节点
    function createTreeNode(node, parentElement) {
      const div = document.createElement('div');
      div.className = 'tree-node';
      div.textContent = node.name;
      
      // 点击事件:切换子节点显隐
      div.onclick = function() {
        const childrenDiv = parentElement.querySelector('.children');
        if (childrenDiv) {
          childrenDiv.style.display = 
            childrenDiv.style.display === 'none' ? 'block' : 'none';
        }
      };
      
      parentElement.appendChild(div);

      // 递归处理子节点
      if (node.children?.length) {
        const childrenDiv = document.createElement('div');
        childrenDiv.className = 'children';
        node.children.forEach(child => createTreeNode(child, childrenDiv));
        parentElement.appendChild(childrenDiv);
      }
    }

    // 渲染根节点
    const treeElement = document.getElementById('tree');
    treeData.forEach(node => createTreeNode(node, treeElement));
  </script>
</body>
</html>

代码解析
  1. HTML 结构

    • 仅需一个 <div id="tree"> 容器,所有节点通过 JavaScript 动态生成。

    • 样式通过 CSS 类名控制(.tree-node 定义节点样式,.children 控制子节点缩进与显隐)。

  2. 核心逻辑

    递归构建节点createTreeNode 函数递归生成 <div> 元素,每个节点绑定 onclick 事件。

    事件处理 :点击父节点时,通过 querySelector 查找子容器,切换其 display 属性实现展开/收起。

    DOM 操作优化:直接操作 DOM 元素而非拼接字符串,便于动态更新和事件绑定。

  3. 交互扩展思路

    动画效果 :添加 CSS transition 属性实现平滑展开效果。

    懒加载 :点击父节点时动态请求子节点数据(需后端配合)。

    多选/折叠 :通过 dataset 属性标记节点状态,实现全选或折叠全部子节点。


总结

字节一面考察的两道题都是经典的场景题,因该是面试中问到了vue的原理,所以顺带考了compile和render的题。

相关推荐
SheepMeMe16 分钟前
蓝桥杯2024省赛PythonB组——日期问题
python·算法·蓝桥杯
随便昵称17 分钟前
蓝桥杯专项复习——前缀和和差分
c++·算法·前缀和·蓝桥杯
清灵xmf20 分钟前
Vue 3 自定义权限指令 v-action
前端·javascript·vue.js·自定义指令
脑子慢且灵22 分钟前
蓝桥杯冲刺:一维前缀和
算法·leetcode·职场和发展·蓝桥杯·动态规划·一维前缀和
一棵树长得超出它自己22 分钟前
jmeter if控制器在loop控制器执行结束后执行
前端·jmeter
姜威鱼1 小时前
蓝桥杯python编程每日刷题 day 21
数据结构·算法·蓝桥杯
CYRUS STUDIO1 小时前
Unidbg Trace 反 OLLVM 控制流平坦化(fla)
android·汇编·算法·网络安全·逆向·ollvm
ゞ 正在缓冲99%…1 小时前
leetcode22.括号生成
java·算法·leetcode·回溯
uhakadotcom1 小时前
AWS Lightsail 简介与实践
后端·面试·github
小卡皮巴拉1 小时前
【力扣刷题实战】矩阵区域和
开发语言·c++·算法·leetcode·前缀和·矩阵