【前端面经 | 小米】2024 面试复盘第四弹——小米

517 阅读4分钟

一面

1. hooks 到底是什么?hooks 的设计理念是什么?解决了什么问题?

  1. hooks 是什么:
    1. 允许开发者在函数式组件中使用状态和其他 react 特性,而不是类 class
  2. hooks 设计理念:
    1. 提高代码复用性
    2. 增强组件可读性
    3. 避免嵌套地狱(class 高阶组件)
    4. 函数式编程
  3. 解决的问题:
    1. 复杂组件难以管理:类组件生命周期包含多个互不相关的逻辑 hooks 可以根据业务逻辑独立使用
    2. 状态逻辑复用困难:高阶组件存在一定局限 难以重复使用共享组件中的逻辑
    3. 类组件的 this 添加学习成本:state useState 使用起来更简单 减少了 this 指向不明的问题

2. react 框架原理是什么?和 vue 框架设计有什么区别?

  1. 模板语法 vs jsx:
    1. vue 使用简介的模板语法 以声明式的方式将数据渲染到页面上 html 结构在 templete 标签中书写
    2. react 的语法写在 js 文件中 使用 js 语法
  2. 数据绑定 vs 单向数据流
    1. vue 双向数据绑定 v-model 视图改变时更新 model model 改变时更新视图
    2. react 单向数据流 属性不允许直接修改 通过 onChange 和 setState 实现双向数据流
  3. 指令系统
    1. vue 存在 v-if v-for 指令
    2. react 通过函数的条件语句实现指令

3. 【笔试】实现大文件上传

二面

1. this 指向问题?

2. this 指向 在实际应用中 有遇到什么问题?怎么解决的?

  1. 类组件+函数组件
  2. 防抖节流 this 指向
  3. 函数式弹窗

3. 在类组件中 改变 this 有没有性能问题?

4. 对于开源组件进行二次开发时 您的关注点是什么?您会怎么进行开发?

5. 如果另一个项目 也想用这个开源组件 除了 copy 代码 还有什么方法?

6. 都是用过哪些第三方库?

  1. zustand
  2. proComponent
  3. ahooks
  4. NextJS

7. 如果让你抉择使用什么库?你会考虑哪些方面?

  1. 项目规模和复杂性
    1. 对于小型项目或简单的应用,可能不需要引入复杂的状态管理库,React 自身的状态管理(通过 useState 和 useReducer 等 Hooks)可能就足够了。
    2. 对于中型到大型项目,或者状态管理变得复杂(如跨组件状态共享、异步操作、全局状态等),我会考虑使用状态管理库。
  2. 功能需求+特性:
    1. 根据项目的具体需求,我会评估不同库提供的功能和特性
    2. 例如,是否需要全局状态管理、时间旅行调试、状态持久化、中间件支持等
  3. 稳定性+性能优化:
    1. 确保库能够高效地处理状态更新和渲染优化
    2. 一些库可能提供了内置的优化机制,如避免不必要的重新渲染、状态持久化等
  4. 灵活性和可扩展性:
    1. 选择的库能够灵活地适应项目的需求变化
    2. 库是否支持插件、中间件或自定义扩展
  5. 学习曲线+社区资源
    1. 文档清晰、学习曲线平缓的库,这样团队成员可以更快地上手
    2. 社区资源:活跃的社区意味着有更多的资源、教程和问题解决方案
  6. 维护性和未来前景:
    1. 库的维护频率、是否有活跃的开发者社区和持续的更新
    2. 库的未来发展规划和兼容性

8. 有没有自己开发过 hooks?有哪些注意事项?

9. react 主要的生命周期有哪些?

10. react 和 vue 有哪些相似之处?有什么区别?

11. 在学习和工作中,最有成就感的事情是什么?

12. 你觉的这个过程中,是技术还是思维还是模式 让你感觉很有成就感?

13. 有没有遇到过沟通上的问题?事后有什么反思?

14. 在学习和工作中 有没有遇到过什么受挫的事情?

三面

1. 前端后续的发展趋势?

  1. 微前端
  2. 大前端

2. 客户端有接触过么?APP 相关

3. 【代码】二叉树的层序遍历

// 定义二叉树节点
class TreeNode {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}
 
// 层序遍历函数
function levelOrderTraversal(root) {
  if (!root) return []
 
  // 创建队列,并将根节点入队
  const queue = [root];
  const result = [];
 
  while (queue.length > 0) {
    // 获取当前层的节点数量
    const levelSize = queue.length;
    const currentLevel = [];
 
    for (let i = 0; i < levelSize; i++) {
      // 出队一个节点
      const node = queue.shift();
      currentLevel.push(node.value);
 
      // 将该节点的左右子节点(如果存在)入队
      if (node.left) {
        queue.push(node.left);
      }
      if (node.right) {
        queue.push(node.right);
      }
    }
 
    // 将当前层的节点值添加到结果数组中
    result.push(currentLevel);
  }
 
  return result;
}
 
// 示例用法
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
root.right.left = new TreeNode(6);
root.right.right = new TreeNode(7);
 
const result = levelOrderTraversal(root);
console.log(result);
// 输出: [[1], [2, 3], [4, 5, 6, 7]]