前端综合技术面试记录

2025-01-10
某互联网公司
前端开发工程师

前端综合技术面试记录

面试日期:2025-01-10
面试公司:某互联网公司
应聘职位:前端开发工程师

面试关键词

JavaScript 基础 | Vue 框架 | TypeScript | Webpack 优化 | 路由权限 | 性能优化


📚 JavaScript 基础

1. letconst 的区别

要点回顾:

  • let:块级作用域,可重新赋值(mutable),不可重复声明(同一作用域)
  • const:块级作用域,绑定不可变(binding immutable),必须初始化;对象/数组的内容可变(属性可改)

实战建议:

  • 默认使用 const,需要重新赋值时再用 let;尽量避免使用 var

代码示例:

const a = { x: 1 };
a.x = 2; // 合法
a = {}; // 报错

let b = 1;
b = 2; // 合法

2. for...infor...of 的区别

要点回顾:

  • for...in:遍历对象的可枚举属性名(包括原型链上的可枚举属性),返回 key(字符串)。不适合数组元素遍历(顺序不保证)
  • for...of:遍历可迭代对象(Array、Map、Set、String、arguments 等),返回 value

实战建议:

  • 数组使用 for...offor / forEach;对象遍历使用 Object.keys()for...in(注意 hasOwnProperty)

代码示例:

for (const key in obj) {
  if (!obj.hasOwnProperty(key)) continue;
  console.log(key, obj[key]);
}

for (const val of arr) {
  console.log(val);
}

🌐 浏览器与性能优化

3. 从输入 URL 到浏览器渲染的全过程

关键阶段:

  1. 输入 URL → 浏览器检查缓存(HSTS、DNS cache)
  2. DNS 解析 → 得到 IP
  3. TCP 三次握手 → 若 HTTPS,多出 TLS 握手
  4. 发送 HTTP 请求(含 Headers、Cookie)
  5. 服务端处理 → Nginx → 应用 → DB / 缓存 → 生成响应
  6. 浏览器接收响应 → 解析 HTML(构建 DOM)
  7. 解析 CSS(CSSOM)、JS(执行) — JS 若无 defer/async 会阻塞解析
  8. 生成 Render Tree → Layout(reflow) → Paint → Composite(合成 GPU 层)
  9. 浏览器渲染到屏幕

优化点:

  • 资源并行加载、HTTP/2、资源压缩、缓存策略、critical CSS、懒加载、服务端渲染(SSR)

4. 首屏优化方案

网络层优化:

  • 启用 HTTP/2 或 HTTP/3
  • 使用 CDN 加速
  • 资源压缩(gzip/brotli)
  • 长缓存 + 版本控制
  • 预连接/预取(<link rel="preconnect">prefetch

解析层优化:

  • 关键 CSS inline(critical CSS)
  • JS 标记 deferasync
  • Code-splitting 减少 bundle 首包体积

渲染层优化:

  • Skeleton / 骨架屏
  • 图片懒加载(srcsetsizes
  • 使用 requestIdleCallback 处理非关键任务

度量指标:

  • 使用 Lighthouse、Web Vitals(FCP、LCP、TTI)持续监控

5. SEO 优化方案

技术实现:

  • SSR/Prerender:保证搜索引擎抓取到完整 HTML
  • Meta 信息:动态设置 title/meta description,使用 JSON-LD
  • URL 规范化:语义化路径、canonical 标签
  • 站点地图:提供 sitemap.xml、robots.txt
  • 性能优化:FCP/LCP 优化间接提升 SEO
  • 社交预览:Open Graph/Twitter Card 标签

推荐框架: Next.js / Nuxt / SvelteKit


💡 JavaScript 进阶概念

6. 闭包(Closure)

要点回顾:

  • 闭包是函数与其词法环境的组合
  • 函数可以访问定义时的外部作用域,即使外部函数执行结束

常见用途:

  • 数据私有化(模块化)
  • 柯里化
  • 函数工厂
  • 保持状态

代码示例:

function makeCounter() {
  let count = 0;
  return function() {
    return ++count;
  }
}
const c = makeCounter(); // c() 每次调用会记住 count

注意事项:

  • 注意内存泄漏(大量闭包持有大对象会影响 GC),必要时释放引用

7. 防抖(debounce)和节流(throttle)

概念区别:

  • 防抖(debounce):事件停止一定时间后才触发(适合输入框搜索、窗口 resize)
  • 节流(throttle):在固定时间间隔内只允许触发一次(适合滚动、鼠标移动)

代码实现:

// debounce
function debounce(fn, wait) {
  let t;
  return function(...args) {
    clearTimeout(t);
    t = setTimeout(() => fn.apply(this, args), wait);
  }
}

// throttle
function throttle(fn, interval) {
  let last = 0;
  return function(...args) {
    const now = Date.now();
    if (now - last >= interval) {
      last = now;
      fn.apply(this, args);
    }
  }
}

实战建议:

  • 使用 lodash 的成熟实现,支持 leading/trailing 参数

8. TypeScript 泛型

要点回顾:

  • 泛型用于描述类型的参数化,增强复用性和类型安全

代码示例:

function identity<T>(arg: T): T {
  return arg;
}
const s = identity<string>('hello'); // s 类型是 string

interface ApiResult<T> {
  code: number;
  data: T;
}
type User = { id: number; name: string };
const r: ApiResult<User> = { code: 0, data: { id:1, name:'A' } };

实战建议:

  • 用泛型封装复用组件/工具(如接口返回类型、表单、容器组件)
  • 合理约束 T extends {} 避免 any

⚡ Vue 框架

9. Vue2 和 Vue3 的主要区别

核心区别:

  • 响应式实现:Vue2 用 Object.defineProperty,Vue3 用 Proxy(支持新增属性监听、更高性能)
  • 性能:Vue3 更快,bundle 更小,Tree-shakable
  • Composition API:Vue3 提供 setup/ref/reactive 等,逻辑复用更优
  • 新特性:Fragment / Teleport / Suspense 原生支持
  • 渲染器:虚拟 DOM、renderer 重写,支持更灵活的自定义渲染

面试亮点:

  • 强调 Proxy 带来的好处:拦截新增/删除属性、数组原生支持、性能优势

10. Object.defineProperty 的缺陷

主要问题:

  • 无法监听属性新增/删除(需递归定义或 Vue.set
  • 对数组变更需重写原型方法(复杂且易出错)
  • 性能问题:深层对象需要递归劫持造成初始化开销
  • 无法拦截 Map/Set 等数据结构操作

解决方案:

  • Vue3 使用 Proxy 彻底解决这些问题

11. computedwatch 的区别

要点回顾:

  • computed:基于依赖缓存,用于声明式计算属性,只有依赖改变才重新计算,适合模板绑定
  • watch:用于执行副作用,可监听数据变化并在变化时运行回调(适合异步或显式副作用)

代码示例:

const count = ref(1);
const double = computed(() => count.value * 2); // 缓存

watch(count, (newV, oldV) => {
  // 执行副作用,比如请求、手动 DOM 操作
});

实战建议:

  • 能用 computed 的就别用 watch;需要做异步或复杂副作用用 watch

📦 Webpack 构建优化

12. Webpack 优化策略

构建体积优化:

  • Tree-shaking
  • Terser 压缩
  • CSS 压缩
  • 去掉无用 polyfill
  • 按需加载
  • 分包(splitChunks)

构建速度优化:

  • 使用 cache-loader 或硬盘缓存
  • thread-loader 多线程构建
  • esbuild/swc 替代 Babel
  • HMR 优化

运行性能优化:

  • Long-term caching(contenthash)
  • preload/prefetch
  • 按需加载(dynamic import)
  • 第三方库 CDN 或 externals

资源优化:

  • 图片压缩
  • SVG sprite
  • 字体子集化

分析工具:

  • webpack-bundle-analyzer 分析体积,定位大依赖

实战建议:

  • 先定位(bundle 分析),再拆包与异步加载
  • 优先替换体积大但使用少的库

🛣️ Vue Router

13. vue-router 底层原理

两种模式:

  • Hash 模式location.hash + hashchange 事件
  • History 模式:HTML5 History API(pushState/replaceState + popstate 事件)

核心机制:

  • Vue Router 维护 currentRoute
  • 通过 matcher(基于 path-to-regexp)把 URL 映射成路由记录
  • RouterView 响应式渲染组件

面试要点:

  • 说出事件 hashchangepopstate
  • 提到动态路由匹配与 addRoute

14. vue-router 动态路由匹配

实现原理:

  • 内部用 path-to-regexp 将路径(含 :param*、正则)转成正则表达式并提取 params
  • 支持嵌套路由:子路由继承父路由 params
  • 可在运行时动态注册路由 router.addRoute()(用于菜单权限懒加载)

实战建议:

  • 权限路由先用路由白名单
  • 登录后从后端获取菜单/权限生成 routes 并 addRoute
  • 然后 replace 到第一个可访问页面

15. 菜单权限控制步骤

实施流程:

  1. 鉴权入口

    • 登录后获取 token
    • 后端返回用户权限/角色或权限码(建议最小粒度)
  2. 后端返回菜单树

    • 后端按权限生成菜单(包含 route path、component 引用、action 权限)
  3. 前端动态生成路由

    • 将菜单树映射成 route record → router.addRoute(...)
    • 未命中的路由重定向到 403/登录页
  4. 前端权限校验

    • router.beforeEach 做路由守卫(检查 token、权限)
    • 在页面/按钮做能力级别判断(v-if 或指令)
  5. 按钮级权限

    • 后端返回 action 列表(create/update/delete)
    • 前端在组件中按权限开关 UI 按钮并控制接口调用
  6. 缓存 & 刷新

    • 路由与权限需持久化(localStorage/sessionStorage)
    • 刷新页面时优先从 token 调用权限接口恢复

安全注意:

  • 后端必须二次校验(前端仅做体验层控制)

📎 大文件上传

16. 大文件上传实战方案

核心策略:

1. 切片上传(Multipart Upload)

  • 前端把大文件分为 N 片(如 5MB)
  • 每片并行上传到后端或直传到对象存储(OSS/S3)
  • 后端或 OSS 支持合并分片
  • 支持断点续传(记录已上传的块),校验 MD5/ETag

2. 直传 OSS(前端直传)

  • 前端获取短期签名(STS / presigned URL)
  • 直接上传至 CDN/OSS,减轻后端压力

3. 断点续传与重试机制

  • 每片成功后记录状态,失败则重试
  • UI 显示进度条和已上传片

4. 并发控制与速率限制

  • 控制同时并发条数(例如 3~6 个并发)避免网络拥塞

5. 压缩/转码(可选)

  • 在前端做图片压缩、视频转码尽可能减小体积

6. 安全校验

  • 后端校验文件类型、大小、病毒扫描(可异步)

实现流程:

  1. 切片并计算每片 MD5/Hash
  2. 请求服务端获取上传授权与已上传片信息
  3. 并发上传未上传的切片到 presigned URL 或后端接口
  4. 上传完成后通知后端合并并返回 final URL
  5. 若中断,基于已上传记录重试

总结

本次面试主要涉及前端全方位的技术知识,涵盖:

  • JavaScript 基础:变量声明、循环遍历、闭包、防抖节流
  • 浏览器原理:渲染流程、首屏优化、SEO 方案
  • Vue 框架:Vue2/3 区别、响应式原理、computed vs watch
  • 工程化:Webpack 优化、构建策略
  • 路由与权限:Vue Router 原理、动态路由、菜单权限控制
  • 实战场景:大文件上传方案

通过这次面试,系统地梳理了前端开发中的核心技术点和实战经验。