文章目录

字节暑期前端一面整理笔记(三十七)

1. Sdk 干什么,你为什么会在公司接触这个业务

答案

SDK 本质上是对某类能力的封装,目的是让业务侧更低成本地接入统一能力。

  1. 常见场景有埋点、登录、支付、上传、AI 能力接入、编辑器能力接入。
  2. 公司里会接触 SDK,通常是因为很多业务线都要复用同一套能力,不能每个项目都从零写一遍。
  3. 一个好的 SDK 要解决接入简单、版本兼容、错误兜底和可扩展的问题。

2. 插件是什么个逻辑

答案

插件机制的核心是“在不改核心代码的前提下扩展能力”。

  1. 一般会预留生命周期或 Hook。
  2. 插件通过注册这些 Hook,把自己的逻辑插进去。
  3. 好处是核心系统保持稳定,扩展能力交给外部实现。
  4. 常见于构建工具、编辑器、CLI、业务平台。

3. sdk 的 treeshaking 前后的大小有没有对比过

答案

SDK 本质上是对某类能力的封装,目的是让业务侧更低成本地接入统一能力。

  1. 常见场景有埋点、登录、支付、上传、AI 能力接入、编辑器能力接入。
  2. 公司里会接触 SDK,通常是因为很多业务线都要复用同一套能力,不能每个项目都从零写一遍。
  3. 一个好的 SDK 要解决接入简单、版本兼容、错误兜底和可扩展的问题。

4. treeshaking 的逻辑

答案

Tree Shaking 的本质是删除“没有被用到的导出代码”。

  1. 它依赖静态分析,所以最适合 ESM。
  2. 常见发生在打包阶段,构建工具会分析依赖图和导出引用关系,把未使用代码标记为可删除。
  3. CommonJS 因为 require 是运行时执行、可动态分支,静态分析能力弱,所以 Tree Shaking 效果受限。
  4. 如果问体积对比,应该回答:会对比打包前后的 bundle 体积、gzip/br 体积和实际加载资源变化。

5. treeshaking 是在哪个阶段进行

答案

Tree Shaking 的本质是删除“没有被用到的导出代码”。

  1. 它依赖静态分析,所以最适合 ESM。
  2. 常见发生在打包阶段,构建工具会分析依赖图和导出引用关系,把未使用代码标记为可删除。
  3. CommonJS 因为 require 是运行时执行、可动态分支,静态分析能力弱,所以 Tree Shaking 效果受限。
  4. 如果问体积对比,应该回答:会对比打包前后的 bundle 体积、gzip/br 体积和实际加载资源变化。

6. treeshaking 在 CommonJS 有什么限制

答案

Tree Shaking 的本质是删除“没有被用到的导出代码”。

  1. 它依赖静态分析,所以最适合 ESM。
  2. 常见发生在打包阶段,构建工具会分析依赖图和导出引用关系,把未使用代码标记为可删除。
  3. CommonJS 因为 require 是运行时执行、可动态分支,静态分析能力弱,所以 Tree Shaking 效果受限。
  4. 如果问体积对比,应该回答:会对比打包前后的 bundle 体积、gzip/br 体积和实际加载资源变化。

7. monorepo 底层逻辑架构是什么样

答案

Monorepo 是把多个相关包放在同一个仓库管理。

  1. 优点是依赖统一、代码共享方便、原子提交和统一 CI 更容易。
  2. 缺点是仓库治理复杂、构建和权限边界需要额外设计。
  3. 它和微前端不是一回事:Monorepo 解决的是代码仓库组织问题,微前端解决的是前端运行时拆分和独立部署问题。

8. md 里面的 ai 相关是什么逻辑

答案

这类题核心是把你的 AI 产品链路说清楚。

  1. 如果当前只支持文字,就直接说明当前能力边界,不要虚构支持图片。
  2. 再补充未来如果扩展图片、文件、多模态,需要新增的协议字段、渲染组件和状态管理。
  3. 项目里 AI 的主链路通常是:用户输入 -> 上下文组装 -> 模型请求 -> 流式返回 -> 前端增量渲染 -> 会话持久化。

9. md 的性能优化逻辑

答案

如果这里指 Markdown 编辑或渲染性能,核心是避免每次小变动都整段重算。

  1. 解析和渲染尽量做增量处理。
  2. 高频输入时做节流、分帧或 Worker 处理。
  3. 大文档场景要控制 DOM 数量和渲染粒度。

10. 有没有其他的性能优化

答案

可以从资源、渲染、交互和缓存几个维度补充。

  1. 资源层:拆包、压缩、懒加载。
  2. 渲染层:虚拟列表、减少重排重绘。
  3. 交互层:防抖节流、长任务拆分。
  4. 缓存层:接口缓存、静态资源缓存。

11. react 周期

答案

如果说的是类组件生命周期,主线是:

  1. 挂载:constructor -> render -> componentDidMount
  2. 更新:shouldComponentUpdate -> render -> componentDidUpdate
  3. 卸载:componentWillUnmount

如果说的是函数组件,可以补充:函数组件没有传统生命周期方法,更多通过 useEffect / useLayoutEffect 描述挂载、更新和卸载阶段的副作用。


12. 虚拟 diff 对比

答案

虚拟 DOM Diff 不是做最优树编辑距离,而是做工程上的高效折中。

  1. 先把旧树和新树做同层比较。
  2. 默认认为不同层级的节点不会跨层复用。
  3. 列表场景通过 key 标识稳定节点,减少错误复用和无效移动。
  4. 这样可以把复杂度控制在可接受范围内。

13. 为什么 hooks 不能写在条件里面,如果一定要写怎么办

答案

Hooks 不能写在条件分支里,是因为 React 依赖固定的 Hook 调用顺序来关联状态。

  1. 某次渲染进了条件、某次没进,Hook 顺序就会错位。
  2. 一旦错位,后面的状态和副作用都会对应错。
  3. 如果一定要做条件逻辑,应该把条件放进 Hook 内部,或者拆成子组件。

14. git 多个 commit 怎么合并一个

答案

本地多个 commit 合并成一个,最常见做法是 git rebase -i

  1. 选择要整理的提交范围。
  2. 把后续提交改成 squashfixup
  3. 最后合成一个新的提交记录。

如果已经推送到公共分支,要谨慎改历史,避免影响别人。


15. sass、less、tailwind css 区别

答案

Sass 和 Less 都是 CSS 预处理器,提供变量、嵌套、函数、混入等能力;Tailwind 则是原子化 CSS 工具类体系。

  1. Sass / Less 更偏“写更强的 CSS”。
  2. Tailwind 更偏“用约束好的类名快速组合界面”。
  3. 预处理器适合已有样式体系的增强,Tailwind 更适合规范统一、组件化程度高的项目。

16. 手撕 bind

答案

手写 bind 要处理两个核心点:绑定 this,以及支持 new 调用。

  1. 返回一个新函数。
  2. 新函数执行时把预置参数和调用参数拼起来,再用 apply 调原函数。
  3. 如果新函数被 new 调用,this 应该指向新实例,而不是原先绑定对象。
  4. 如果要完整实现,还要处理原型链继承。

17. 数字转汉字整数

答案

这题一般按“分段处理”来做。

  1. 先把数字按个、十、百、千、万、亿这些单位拆开。
  2. 每四位作为一个分段处理,再拼接“万、亿”等大单位。
  3. 重点难点是连续零只读一个零,以及十几开头时通常省略“一”。