文章目录

牛客面经整理:字节前端风控一面(八股 / 工程化 / 安全 / JS)(二十)

收录日期:2026-04-28
关键词:前端、CSS、Tailwind、Vue2/Vue3、浏览器缓存、CORS、CSRF、Cookie、JWT、Event Loop、async/defer、Vite、Tree-shaking、手写题

1. CSS 盒模型有哪些参数?box-sizing 有什么用?

参考答案

  • 盒模型从内到外:content(内容区)→ padding(内边距)→ border(边框)→ margin(外边距)。
  • width/height 默认只作用在内容区(box-sizing: content-box)。
  • box-sizing: border-boxwidth/height 包含 padding + border + content,更利于做布局(避免计算)。

2. 多列布局用什么更好?(Grid / 多列 / 表格)

参考答案

  • 常见选择:
    • 等高、二维对齐明显:优先 CSS Grid
    • 一维流式布局:Flex 更常用。
    • 报刊式“分栏流”(内容自动从一列流到下一列):column-count/column-width
  • 不建议用 table/隐藏表格做布局:语义差、可访问性与响应式维护成本高。

3. Tailwind 与传统 CSS/预处理器的主要区别?

参考答案

  • Tailwind:以“原子类/工具类”为主,通过组合 class 直接表达样式,减少手写 CSS 与命名成本。
  • 传统 CSS:更多依赖语义类名 + 样式抽象;复用靠 BEM/组件化/变量 mixin 等。
  • 工程化差异:Tailwind 依赖构建期扫描(purge/content)做按需生成与裁剪,最终产物更可控。

4. Tailwind 的缺点/风险点?

参考答案

  • 可读性两极分化:类名堆叠,长 class 需要格式化/抽离(@apply、组件封装、class 合并工具)。
  • 约束与设计系统:需要 theme/tokens 统一,不然容易“随手写值”导致风格漂移。
  • 构建期扫描坑:动态拼接类名可能被裁剪;需要 safelist 或显式枚举。

5. Vue2 和 Vue3 响应式最大的差异?

参考答案

  • Vue2:基于 Object.defineProperty 劫持 getter/setter;数组与新增属性有局限(需 Vue.set 等)。
  • Vue3:基于 Proxy 代理对象,支持更完整的拦截(新增/删除属性、数组索引等),实现更一致,性能也更好。
  • 组合式 API/编译优化也常被提及,但“响应式底层”主要是 defineProperty vs Proxy

6. 浏览器缓存工作方式(强缓存/协商缓存)

参考答案

  • 强缓存:命中时不发请求(或不走网络),常用 Cache-Control: max-age/immutableExpires(旧)。
  • 协商缓存:发条件请求,服务端根据 ETag/Last-Modified 判断,没变化返回 304 Not Modified
  • 常见策略:带 hash 的静态资源走强缓存;HTML 入口与 API 更偏协商/短缓存,便于更新。

7. 常见缓存相关头有哪些?(举例说明作用)

参考答案

  • Cache-Controlmax-ageno-cacheno-storepublic/privates-maxageimmutable 等。
  • ETag / If-None-Match:实体标签与条件请求。
  • Last-Modified / If-Modified-Since:基于修改时间的协商缓存(精度较低,可能误判)。
  • Vary:告诉缓存“不同请求头组合会得到不同响应”(如按 Accept-EncodingOrigin 变化)。

8. 跨域 / 同源策略 / CORS 是什么?

参考答案

  • 同源:协议/域名/端口一致才算同源;同源策略限制 JS 读取跨域响应(并非禁止发请求)。
  • CORS:服务端用响应头授权跨域访问(如 Access-Control-Allow-Origin)。
  • 预检(OPTIONS):非简单方法、非简单头或 Content-Type: application/json 等会触发,需服务端正确响应允许的方法/头/凭证。
  • Cookie:跨域携带凭证需要前端 credentials + 服务端 Access-Control-Allow-Credentials: true,且 Allow-Origin 不能是 *

9. CSRF 是什么?如何防?

参考答案

  • CSRF:利用浏览器自动携带 Cookie 的特性,诱导用户在已登录态下对站点发起“非预期请求”。
  • 防护:
    • 关键接口校验 CSRF Token(同步到表单/请求头)。
    • SameSite Cookie(Lax/Strict/None; Secure)。
    • 校验 Origin/Referer(作为辅助手段)。
    • 对敏感操作做二次确认/验证码/风控。

10. Cookie vs JWT:区别、优缺点与安全点?

参考答案

  • Cookie(会话 ID):
    • 状态可放服务端(更易做吊销/黑名单/会话管理)。
    • 风险:CSRF;可通过 HttpOnly 防 XSS 直接读取。
  • JWT:
    • 通常是“自包含”令牌(header.payload.signature),服务端不必存会话但常配合黑名单/短期 token + refresh。
    • payload 是 Base64URL 编码,不是加密,不要放敏感信息;安全性靠签名防篡改。
    • 风险:XSS 盗取(若放 localStorage);过期与吊销设计要清晰(短过期 + refresh + rotate)。

11. JS Event Loop:宏任务/微任务、requestAnimationFrame

参考答案

  • 事件循环流程(简化):
    • 执行一个宏任务(script、setTimeout、I/O、UI 事件…)
    • 清空微任务队列(Promise then/catch/finally、queueMicrotask、MutationObserver)
    • 进入渲染(可能发生)/requestAnimationFrame 回调在渲染前触发
    • 继续下一个宏任务
  • 典型输出题:同步先执行;微任务早于下一轮宏任务。

12. 输出顺序题:1 4 3 2 为什么?

参考答案

console.log(1)
setTimeout(() => console.log(2), 0)
Promise.resolve().then(() => console.log(3))
console.log(4)
  • 同步:14
  • 微任务:3
  • 下一轮宏任务:2

13. async / defer 的区别?

参考答案

  • defer
    • 脚本下载不阻塞解析 HTML;
    • 执行会推迟到 HTML 解析完成后;
    • 多个 defer 脚本按顺序执行。
  • async
    • 脚本下载不阻塞解析 HTML;
    • 下载完成就尽快执行(可能打断解析);
    • 多个 async 执行顺序不保证。

14. Vite 为什么开发环境快?

参考答案

  • 开发时用原生 ESM:按需请求模块,不做整包打包。
  • 预构建:用 esbuild 对依赖做预打包/缓存,加速冷启动与请求数。
  • HMR 粒度更细:改动只影响局部模块链路。

15. Tree-shaking 机制与“摇不掉”的原因?

参考答案

  • 依赖前提:ESM 静态分析 + DCE(死代码消除)。
  • 摇不掉常见原因:
    • 使用 CommonJS(动态 require)导致静态分析困难。
    • 模块有副作用(顶层改全局、注入样式等),打包器不敢删。
    • 未正确标注 sideEffects 或聚合导出/不精确导入导致整包引入。

16. 手写题:展平多层嵌套数组

参考答案

  • 递归:
    • 遍历元素,遇到数组递归展开,否则 push。
  • 迭代(栈):
    • 用栈模拟 DFS/BFS,注意保持顺序可用 unshift 或倒序入栈。
  • JS 内置:arr.flat(Infinity)(面试可提,但通常希望手写)。