# 自检(面试手册)

简历

  1. 大厂简历筛选有一套机制,有大厂经历或学历好或经验匹配的会比较容易通过筛选,缺少光环的需要有其他东西来证明,比如优秀的项目经历,参与过好的开源项目等

  2. 简历上描述的技术/内容/项目确保自己是真的熟悉/掌握,看看每个技能是不是自己真的掌握了,能说出个 1.2.3;每个项目是否自己能说清楚,一些细节是否了解,有哪些复盘点,是否有改进空间

  3. 简历上描述的应该是与目标岗位直接/间接相关的,其他的比较优秀的点可以一笔带过,不需要花大篇幅介绍这些与目标岗位不符的能力

  4. 面试官简历评估时也会看跳槽频率,像 1 年 1 跳这种会被评为不稳定,这时除非学历/经历特别出色的,其他基本就不通过了

面试

  1. 面试除了技能/项目知识外,状态也很重要;接到面试电话说明简历评估通过了,时间可以你自己定,如果没准备好,可以把时间拉长些,给自己一些准备时间;要求当场面试的可以礼貌拒绝然后定一个合适的时间

  2. 对不同工作年限的同学会有不同的要求,校招主要看潜力,所以基础(计算机、网络)和算法会考得比较多;1~3 年除了潜力外还看经验是否与业务匹配,项目经验;3~5 年看是否有独挡一面的能力,需要在技术上有较好的深度,在做事情方面有自己的一套;大于 5 年的除了深度外对广度也有要求,且需要有跨端和架构设计的能力,对于管理岗位也会看带团队的能力

  3. 面试时遇到不会的不用慌,每个人的知识面不一样,碰到不会的很正常,但可以积极思考,首先坦诚表示没有了解过相关知识,然后以现有的知识体系思考下这个问题,说明思路,合理猜测结果

  4. 有时会有面试官会刻意施加压力,这时不在于问题回答的是否正确,而在于是否能在这些压力下仍然能够理性思考,面对面试官的每个问题,可以尝试想下面试官问这个问题的背后目的是什么

# 面试要点解析

# 前端基础

javascript

  • 原型链
  • 继承
  • 作用域
  • 闭包
  • 变量提升
  • this 的指向
  • 立即执行函数
  • instanceof 原理
  • bind 的实现
  • apply 和 call
  • 柯里化
  • v8 垃圾回收机制
  • 浮点数精度
  • new 操作符
  • 事件循环机制
  • promise 原理
  • generator 原理

css

  • 盒子模型
  • CSS 选择器
  • BFC
  • position
  • flex 布局
  • css 优先级
  • 双飞冀/圣杯布局
  • CSS3 新特性
  • CSS 样式隔离
  • CSS 性能优化
  • 层叠上下文
  • div 居中
  • 浮动

html&浏览器

  • 行内元素、块级元素
  • 跨标签页通信
  • history 和 hash 两种路由
  • DOM 树
  • 事件模型
  • 缓存策略
  • 浏览器架构
  • 浏览器工作原理
  • 内存泄露

性能

  • 前端性能优化指标 RAIL
  • 前端性能优化手段
  • 重排和重绘
  • 白屏
  • 大量图片加载优化
  • 描述下浏览器从输入网址到页面展现的整个过程
  • 动画性能
  • 渲染合成层

工程化

  • 模块化机制
  • tree shaking
  • uglify 原理
  • babel 原理
  • webpack 工作流程
  • webpack 插件机制
  • webpack loader 机制
  • 前端微服务

# 框架

React

  • 合成事件
  • virtual dom
  • setState 过程
  • fiber
  • 高阶组件
  • 错误处理
  • 性能优化

Redux

  • redux 核心原则
  • redux 核心逻辑

Vue

  • 数据绑定原理
  • computed 和 watch
  • slot
  • next tick 原理
  • keep alive

# 算法

算法

  • 动态规划:斐波那契数列 ok
  • 数组:合并二维有序数组成一维有序数组 ok
  • 链表:反转链表
  • 链表:链表有环
  • 堆栈队列:判断括号字符串是否有效 ok
  • 返回数组中第 k 个最大元素 ing
  • 找出数组中和为 sum 的 n 个数 ing
  • 贪心:具有给定数值的最小字符串 ok
  • 二叉树:最大深度
  • 二叉树:层次遍历
  • 剪枝:判断数独是否有效
  • 二分查找:求解平方根
  • 字典树:实现一个字典树
  • 动态规划:爬楼梯问题 ok
  • 动态规划:最短距离
  • 数据结构:LRU 缓存
  • 翻转二叉树

编程题

  • 实现一个 trim 方法
  • 实现一个 deepClone 方法
  • 实现 add(1)(2)(3)
  • 大数相加
  • 拍平数组
  • 实现防抖函数
  • 实现节流函数
  • 实现字符串翻转
  • 数组去重
  • 实现千位分隔符
  • 判断是否是回文数
  • 实现一个模板引擎
  • 判断一个数是否是素数
  • 获取 n 以内所有的素数

# 基础

操作系统

  • 进程和线程
  • 进程通信
  • 进程调度策略
  • 死锁
  • IO 多路复用

网络

  • 七层网络模型
  • http
  • https
  • http2.0
  • http3.0
  • websocket
  • tcp
  • udp

# 大前端

Node

  • 模块机制
  • require 原理
  • 事件循环
  • cluster 原理
  • 流机制
  • pipe 原理
  • 守护进程
  • 进程通信
  • 异常处理

# 其他

设计架构

  • 常用设计模式
  • 重构
  • MVVM
  • MVC
  • MVP

开放问题

  • 最近看的书
  • 平常的学习途径
  • 你比较擅长哪一块,不足的地方在哪里

# 模拟题

# (一)

react setState 是同步还是异步 setState 在 React 的合成事件和生命周期中通常是异步(被批量合并),在原生事件或 setTimeout 中可能是同步。React 18 引入自动批处理,更多场景被异步批量处理。要可靠读取更新后状态可使用 setState 的回调或 useEffect(函数组件)。
什么是高阶组件,请举例说明 高阶组件(HOC)是一个函数,接受组件并返回增强后的组件。用于复用逻辑。 示例:const withAuth = (Comp) => props => isAuth ? :
解释一下原型链 每个对象有内部属性 [[Prototype]](通常通过 __proto__ 访问),查找属性时先查对象本身,找不到就沿着原型链向上查,直到 null。构造函数的 prototype 属性是实例对象的原型来源。
instanceof 原理 instanceof 检查右侧构造函数的 prototype 是否在左侧对象的原型链上:让 obj = obj.__proto__,循环比较 obj === C.prototype,直到 null 返回 false。
apply 和 call 的作用及区别 都是改变函数执行时的 this 指向并立即调用。区别在于参数传递:call(fn, thisArg, arg1, arg2, ...);apply(fn, thisArg, [arg1, arg2, ...])。
position 有哪些值,作用分别是什么 static(默认,不脱离文档流)、relative(相对定位,保留原位置)、absolute(绝对定位,脱离文档流,相对于最近定位祖先)、fixed(相对于视口固定)、sticky(根据滚动在相对/固定间切换)。
说下你对 DOM 树的理解 DOM 是浏览器把 HTML 解析成的节点树,表示文档结构。JS 操作 DOM 会触发重绘/重排。DOM 与 CSSOM 合并成渲染树用于布局与绘制。
重排和重绘是什么,有什么区别 重排(reflow/layout):元素几何信息改变,需要重新计算布局(开销大)。重绘(repaint):样式改变影响绘制但不影响布局(如颜色),开销较小。某些操作会同时触发两者。
https 加密过程是怎样的 HTTPS 基本流程:客户端发起 TLS 握手 -> 协商协议版本和加密套件 -> 服务器发证书(公钥) -> 客户端校验证书并生成随机密钥(或协商密钥交换如 ECDHE),用服务器公钥加密后发送 -> 双方生成对称会话密钥 -> 用对称加密传输数据。握手保证机密性、完整性与身份认证。
实现 add(1)(2)(3) 可用函数返回函数并重写 toString/valueOf,例如: const add = a => b => b ? add(a+b) : a; 或用可调用对象累加并重写 valueOf,在最后求值时得到总和。

# (二)

react 为什么需要合成事件 合成事件统一浏览器差异、提高性能(事件委托到 document 根,减少真实 DOM 事件数量),并便于在 React 生命周期中控制事件行为(如批量更新)。
为什么有时 react 两次 setState,只执行一次 因为 React 会对 setState 做批量合并(同一事件循环中的多次 setState 合并为一次更新),并且如果使用对象形式,后一次可能覆盖前一次;使用函数式 setState 可避免覆盖问题。
redux 有哪些原则 - 单一状态树(单一 store) - 状态只读(通过 action 改变) - 使用纯函数 reducer 来描述如何更新状态(不可有副作用)
es5 实现继承 常见模式:构造函数继承(call)、原型链继承、组合继承(构造 + 原型)、寄生组合继承(最优,借助 Object.create)。 示例寄生组合:Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; Parent.call(this,...);
实现一个 promise 核心要点:三种状态 pending/fulfilled/rejected,then 返回新 promise,处理异步回调和链式调用,处理 resolve 值为 promise 的情况。实现需要维护回调队列并在状态变化时异步执行回调。
CSS 选择器有哪些 基础:元素、类、id;组合符:后代、子选择、相邻、通用;属性选择器、伪类(:hover/:nth-child)、伪元素(::before)、组合选择器(:not)、分组选择器(,)。
说下事件模型 浏览器事件模型:捕获阶段 -> 目标阶段 -> 冒泡阶段(除非 stopPropagation)。现代 DOM3 事件可通过 addEventListener 的第三个参数选择捕获或冒泡,也可调用 stopImmediatePropagation。
如何减少白屏的时间 优化首屏加载:减小首屏资源体积(gzip/压缩/拆分)、服务端渲染或预渲染、懒加载、使用关键 CSS inline、CDN 加速、资源优先级控制(preload/prefetch)。
3 次握手过程 1. 客户端发送 SYN(seq=x)。 2. 服务端回复 SYN+ACK(seq=y, ack=x+1)。 3. 客户端回复 ACK(ack=y+1)。建立连接,双方同步初始序列号。
判断链表是否有环 快慢指针(Floyd):快指针每次走两步,慢指针每次走一步,若相遇则有环;若快指针到 null 则无环。

# (三)

react 合成事件是什么,和原生事件的区别 合成事件是 React 的跨浏览器包装,事件委托到根节点,复用事件对象池(旧版本)。区别:API 统一、性能优化(委托)、在 React 生命周期内可实现批处理;但可通过原生事件直接绑定获取真实事件。
react 如何处理异常 类组件提供 componentDidCatch(error, info) 和 static getDerivedStateFromError,用于捕获子组件渲染错误并降级显示。函数组件可用 Error Boundary(用类组件实现)或 useEffect 捕获异步错误,或全局 window.onerror。
闭包的作用和原理 闭包是函数与其定义时的词法环境的组合。作用:封装私有变量、实现函数工厂和部分应用、维护状态。原理:执行环境中的活动记录被函数引用而不被回收,形成持久化作用域。
0.1+0.2 为什么不等于 0.3 浮点数使用二进制表示,0.1 和 0.2 无法精确表示,计算时产生二进制小数误差,导致结果略有偏差。常用解决:四舍五入、乘以基数取整、使用十进制高精库(decimal)。
什么是 BFC,BFC 有什么作用,如何形成 BFC BFC(块级格式化上下文)是一个独立渲染区域,内部布局不影响外部。作用:清除浮动、避免 margin 折叠、限制子元素影响等。触发条件:display: flow-root/flex/inline-block/table-cell/table-column etc; position: absolute/fixed; overflow 不为 visible 等。
浏览器缓存策略是怎样的 常见策略:强缓存(Cache-Control/Expires)——直接命中;协商缓存(ETag/Last-Modified + If-None-Match/If-Modified-Since)——服务器 304 验证。优先使用强缓存,合理设置版本号和 cache 控制。
你知道的前端性能优化手段有哪些 压缩与合并资源、代码拆分与懒加载、CDN、图片优化(格式/尺寸/懒加载)、减少重排重绘、使用缓存、服务端渲染、预加载/预连接、减少资源请求数。
前端模块化机制有哪些 CommonJS(同步,Node),AMD(异步,浏览器),UMD(兼容),ES Modules(静态分析,import/export,浏览器/构建工具支持)。
http2.0 做了哪些改进 二进制分帧、多路复用(单连接并发多个流)、头部压缩(HPACK)、服务端推送、优先级机制,减少了队头阻塞并提高利用率。
求解平方根 可用 Math.sqrt;面试实现可用二分法或牛顿迭代(Newton-Raphson)快速逼近平方根。

# (四)

react 为什么需要 fiber Fiber 重构为可中断、可恢复的渲染算法,支持增量渲染与优先级调度,提升响应性(避免长任务阻塞渲染),使 React 更易实现并发特性。
redux 中间件机制 中间件是增强 dispatch 的函数链,形如 store => next => action => result。通过 compose 把中间件串起来,允许在 action 到达 reducer 前做异步、日志、异常处理等。
bind 的实现 实现要返回一个新函数,调用时 this 指向指定对象,并支持部分应用参数,且当作为构造函数使用时保持原函数的原型行为(new 时忽略绑定的 this)。 示例简化:Function.prototype.bind = function(ctx, ...args) { const fn=this; return function(...rest){return fn.apply(this instanceof fn ? this : ctx, args.concat(rest))} }
说下 generator 原理 Generator 是可暂停的函数,yield 暂停并返回值,next 恢复执行并可传入值。底层依赖状态机处理执行上下文、保持堆栈与作用域,用于实现协程、异步流程控制(配合 yield + Promise 作异步序列)。
flex 布局有什么好处 简化一维布局(横或纵方向),易于实现对齐、顺序调整和自适应伸缩,减少浮动/定位的 hack,响应式布局更直观。
如何定位内存泄露 使用浏览器 DevTools 的 memory heap snapshot、allocation timeline 和堆快照对比,查找 Detached DOM、未清理的定时器/事件监听器、全局引用或闭包持有过期大对象。
渲染合成层是什么 合成层(layer)是 GPU 绘制单位(如具有 transform/opacity 或 will-change 的元素会升为独立层),可以在合成阶段单独绘制和合并以提高动画性能、减少重绘代价。
babel 是什么,怎么做到的 Babel 是 JS 转译器,可把新语法/JSX/TypeScript 转译为向后兼容的 JS。通过 AST(解析 -> 转换 -> 生成)和插件系统对语法树做访遍与替换实现转换。
http2.0 有哪些不足,http3.0 是什么 http2 的不足:虽然有多路复用但仍受 TCP 的队头阻塞影响;复杂的实现与中间代理兼容性问题。HTTP/3 基于 QUIC(基于 UDP)解决了 TCP 层队头阻塞、集成加密与更快的连接建立。
实现一个发布订阅模式 核心有订阅列表、on/subscribe、off/unsubscribe、emit/trigger。示例:const bus = { _map:{}, on(k,f){(this._map[k]||=(this._map[k]=[])).push(f)}, off(k,f){...}, emit(k,...args){(this._map[k]||[]).forEach(fn=>fn(...args))} }。

# (五)

vue 的数据绑定机制是如何实现的 Vue2 使用 Object.defineProperty 劫持 data 的 getter/setter,收集依赖(Dep)并在数据变更时通知 watcher 更新;Vue3 用 Proxy 实现响应式,解决数组、属性新增等限制并性能更好。
vue next tick 实现原理 nextTick 将回调放入微任务队列(Promise.then / MutationObserver / setImmediate / setTimeout 的 fallback),确保在 DOM 更新并批处理完成后执行。
谈谈变量提升 在 JS 中声明会被提升:var 的声明被提升但赋值不提升(初始为 undefined);function 声明整体提升;let/const 不提升到可用阶段(存在暂时性死区)。
new 操作符具体做了什么 1. 创建空对象 obj;2. 设置 obj.__proto__ = Constructor.prototype;3. 将 this 指向 obj 并执行构造函数(Constructor.call(obj, ...args));4. 若构造函数返回对象则返回该对象,否则返回 obj。
介绍下盒子模型 内容(content)、内边距(padding)、边框(border)、外边距(margin)。盒模型有标准盒(content-box)和替代盒(border-box,width 包含 padding 与 border)。
有哪些方式可以使 div 居中 水平居中:外联块 margin:0 auto;或 flex: justify-content:center;或 text-align:center(inline)。垂直居中:flex align-items:center;绝对定位 + transform(-50%,-50%);表格/line-height(特定场景)。
有听过前端性能优化指标 RAIL 吗 RAIL 指导性能优化的四个维度:响应(Response)、动画(Animation)、载入(Idle/Idle + Load)、可交互(Load);关注不同阶段的目标耗时(如交互 <100ms,动画 60fps)。
进程和线程的区别 进程是资源分配单位,有独立地址空间;线程是 CPU 调度单位,属于进程,多个线程共享进程资源但有独立栈。线程切换比进程切换开销小。
tcp 滑动窗口是什么 TCP 流量控制机制:接收方通告窗口大小(可接收的剩余缓冲区),发送方根据窗口控制未确认数据量,实现流控与避免拥塞配合拥塞控制算法。
实现一个斐波那契数列 递归(简单但慢):f(n)=f(n-1)+f(n-2)。动态规划/迭代更优:用循环或缓存 O(n) 时间 O(1) 空间;可用矩阵快速幂或 Binet 公式做 O(log n)。

# (六)

vue 的 computed 和 watch 的区别 computed 是基于依赖缓存的计算属性,适合基于响应式数据的同步计算;watch 用于响应式数据变动时执行副作用(异步或复杂逻辑)。computed 更适合表现值,watch 更适合监听变化执行任务。
说下 vue 的 keep alive 是 Vue 的抽象组件,用于缓存组件实例和 DOM(基于 include/exclude 与 max),切换时避免销毁,保留组件状态与性能优化。
什么是立即执行函数 IIFE(立即调用函数表达式):(function(){ /*...*/ })(),用于创建独立作用域、防止污染全局并立即执行。
谈下事件循环机制 JS 的事件循环(以浏览器为例):执行栈执行同步任务 -> 微任务队列(Promise.then、MutationObserver)在每个宏任务结束前清空 -> 宏任务队列(setTimeout、I/O、UI 事件)逐个执行 -> 重复。Node 有额外阶段如 timers、check、close。
css 优先级是怎么计算的 权重计算:内联样式 > id 选择器(100) > 类/伪类/属性选择器(10) > 元素/伪元素选择器(1)。选择器权重按位相加,权重大则优先;相同权重以后加载的样式优先;!important 可覆盖但同级别仍比权重规则。
CSS 相关的性能优化 避免强制同步布局(查询 layout 属性如 offsetWidth)、减少重排(批量修改、使用 transform/opacity 做动画)、合并样式变更、使用 will-change 谨慎提升、图片压缩与懒加载、使用适当选择器避免过度匹配。
谈下 webpack loader 机制 Loader 在模块被打包前处理资源,链式调用(从右到左/从下到上),每个 loader 接收内容并返回转换后的内容(或异步回调)。Loader 主要用于处理非 JS 资源或对源码进行转译。
进程通信方式有哪些 共享内存、信号、管道(pipe)、命名管道(FIFO)、套接字(socket)、消息队列、远程过程调用(RPC)。浏览器/前端相关还包括 postMessage、WebSocket、BroadcastChannel、SharedWorker 等。
爬楼梯问题 经典:有 n 阶楼梯,每次可走 1 或 2 步,求方法数,等同于斐波那契数列,递推 f(n)=f(n-1)+f(n-2),可用 DP 或矩阵快速幂优化。
实现一个 trim 方法 简易实现:String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,''); }。注意处理 Unicode 空白可用更复杂正则或 ECMAScript 标准内置方法。

# (七)

react fiber 有哪些优点,怎样做到的 优点:可中断渲染、优先级调度、增量渲染与更好的交互响应性。通过把渲染工作分解为小任务(fiber 节点)并在空闲时间逐步完成实现。
谈谈你对作用域的理解 作用域是变量可访问的区域。JS 有全局作用域、函数作用域、块级作用域(let/const)。词法作用域由代码写时决定,闭包是作用域与函数结合的产物。
双飞冀/圣杯布局 两种常见居中/布局方案:圣杯布局通常指中间自适应两侧定宽布局(使用负边距或 flex);双飞冀(传统术语可能指“三栏布局”或古老布局技巧)。面试中可用 flex 或 grid 轻松实现三栏并保证中间自适应。
浮动元素会造成什么影响,如何清除浮动 浮动会使父容器高度塌陷(不包含浮动子元素)。清除浮动方法:父容器设置 overflow:auto/hidden;使用 clearfix(伪元素清除);或把父元素设为 flex/grid/flow-root。
网站首页有大量的图片,加载很慢,如何去优化呢? 图片压缩/更优格式(WebP/AVIF)、按需加载(lazy loading)、使用 CDN、图片尺寸响应式(srcset/picture)、占位图或 LQIP、懒预加载关键首屏图片、合并雪碧图(小图)。
描述下浏览器从输入网址到页面展现的整个过程 DNS 解析 -> 建立 TCP/TLS 连接 -> 发送 HTTP 请求 -> 服务器响应 -> 浏览器解析 HTML 构建 DOM、解析 CSS 构建 CSSOM -> 构建渲染树 -> 布局(reflow) -> 绘制(paint) -> 合成层并在屏幕上呈现;随后 JS 执行可能修改 DOM 触发重排/重绘。
uglify 原理的是什么 压缩 JS 一般包括解析生成 AST、做作用域分析与常量折叠、去除无用代码(dead code elimination)、缩短变量名(mangling)、生成最小化代码。UglifyJS 是常见工具,基于 AST 操作。
tcp 重试机制 TCP 有重传机制:基于超时重传(RTO)和快速重传(收到重复 ACK 达到阈值触发),结合拥塞控制(慢启动、拥塞避免、快重传/快恢复)调整发送窗口和速率。
层次遍历二叉树 层序遍历(广度优先)用队列:先把根入队,循环取出节点,访问并把子节点入队,直到队列空。可扩展为按层输出或记录深度。
实现节流函数 节流(throttle)在一定时间间隔内只允许函数执行一次。实现方式:时间戳法(记录上次执行时间)或定时器法(执行后设定定时器禁止再执行),两者可结合以适配立即与延迟执行策略。

# (八)

react 有哪些性能优化的点 避免不必要渲染(PureComponent、memo、shouldComponentUpdate)、列表 key 合理使用、懒加载组件、拆分代码、避免匿名函数和无谓 prop 改变、使用 useMemo/useCallback、避免重排重绘、虚拟化长列表(react-window)。
v8 垃圾回收机制 V8 使用分代垃圾回收:新生代(Scavenge,复制算法)和老生代(Mark-Sweep / Mark-Compact)。通过标记-清除和压缩减少碎片,并使用增量与并发标记降低停顿。
CSS 样式隔离手段 命名规范(BEM)、CSS Modules、Scoped CSS(Vue)、Shadow DOM(Web Components)、CSS-in-JS、后缀/scope 前缀化或构建时自动加前缀。
行内元素、块级元素有哪些,区别是什么 块级元素(div, p, h1 等)独占一行,可以设置宽高;行内元素(span, a, img 等)不独占行,宽高通常不起作用(img 除外)。还有 inline-block 兼具两者特性。
聊下你知道的浏览器架构 典型浏览器分层:UI 层(浏览器 chrome)、浏览器内核(网络层、渲染引擎、JS 引擎)、渲染引擎(Blink/WebKit)、JS 引擎(V8/SpiderMonkey)、存储(Cache、IndexedDB)、网络栈、插件/扩展等。
是否有写过 webpack 插件 (回答面试时可据实叙述)Webpack 插件通过 Tapable 的钩子扩展构建流程,插件实现 apply(compiler) 并在合适的 compiler/hook 上注册回调,访问 compilation、模块和资源以修改输出。
websocket 建立过程 浏览器向服务器发起 HTTP 升级请求(Upgrade: websocket),双方完成握手(基于 Sec-WebSocket-Key/Accept 校验),之后连接在 TCP 上保持并进行双向全双工数据传输。
合并二维有序数组成一维有序数组 类似归并排序的合并过程:使用多个指针分别指向每个数组当前元素,取最小值推入结果并移动对应指针。若数组数量多可用最小堆(优先队列)优化。
实现防抖函数 防抖(debounce)在一段时间内只执行最后一次调用:每次调用清除前一个定时器并设置新定时器,延迟后执行。立即执行版本可在第一次触发时立即执行并在随后延迟期间忽略。
最近看了什么书,有什么心得 (面试回答应真实)示例:读过《你不知道的 JavaScript》系列,理解了作用域与闭包、异步机制;《高性能网站建设指南》帮助理解性能优化策略。心得:理论结合实践,多写多测。

# (九)

CSS3 有哪些新特性 Flexbox、Grid、动画与过渡、transform、变换函数、媒体查询增强、变量(CSS Custom Properties)、滤镜(filter)、多列布局、渐变、计算函数(calc)。
层叠上下文是什么 层叠上下文(stacking context)是元素及其子元素绘制时的独立 z-index 层级环境,触发条件包括 position + z-index、opacity <1、transform、isolation、mix-blend-mode 等。不同上下文间互不干扰。
history 和 hash 两种路由方式的最大区别是什么? history(基于 History API)路径看起来像正常 URL,需要服务器配置回退到入口文件以支持直接访问;hash 使用 URL 的 # 切片,不会发送到服务器,兼容性好但 URL 可读性差。
动画性能如何优化 使用 transform/opacity 做动画避免触发布局,使用 requestAnimationFrame,开启合成层(will-change)谨慎,减少重绘区域,硬件加速与合适的帧预算(60fps),避免在动画中进行昂贵 JS 运算。
tree shaking 是什么,有什么作用,原理是什么 Tree shaking 是消除未引用代码(死代码消除)的技术,主要用于 ES Module(静态 import/export),构建工具通过静态分析 AST 判定未使用导出并剔除,减小打包体积。
webpack 工作流程是怎样的 从入口开始解析模块依赖 -> 应用 loader 转换文件 -> 生成模块图 -> 应用插件处理 compilation -> 输出打包后的 bundle -> 可选进行代码分割与优化。核心数据结构是 compilation 和 module graph。
什么场景下会用策略模式 当有一组算法或行为可互换且希望在运行时切换时使用策略模式;通过把不同策略封装为独立类/函数并在上下文中选择,便于扩展与维护(比如不同支付方式、路由策略等)。
找出数组中和为 sum 的 n 个数 可用回溯(DFS)或排序后双指针(针对 k=2);对于 k>2 可递归转化为 k-1 问题或使用哈希、剪枝与排序优化。时间复杂度随 k 增大较高。
判断括号字符串是否有效 用栈,遍历字符,遇左括号入栈,遇右括号检查栈顶是否匹配,最后栈空则有效;同时检查长度奇偶和提前出错情况。
平常的学习途径 多渠道结合:阅读官方文档与权威书籍、实践项目、阅读源码、参加技术分享/社区、刷题与总结笔记、通过博客/视频学习新技术并实战验证。

# (十)

node 模块机制是怎样的 Node 使用 CommonJS 模块:每个模块被包装成函数(function(exports, require, module, __filename, __dirname){...}),通过模块缓存避免重复加载,exports/module.exports 导出接口,require 负责加载并解析依赖。
node require 具体实现是什么 require 会先解析模块路径(相对/绝对/核心模块/第三方模块),查找缓存,读取文件(.js/.json/.node),对 .js 文件编译包装执行(vm.runInThisContext),并返回 module.exports。还有模块解析算法(node_modules 层级查找)。
node 事件循环与浏览器的哪些不一样 Node 的事件循环有多个阶段(timers、pending callbacks、idle/prepare、poll、check、close),并有 microtask(process.nextTick 优先于 Promise)。浏览器的宏/微任务模型略有不同,且 Node 更关注 I/O。
cluster 原理是怎样的 cluster 模块利用多进程(fork)在多核机器上复制 Node 进程,每个 worker 运行事件循环,通过主进程负载分发连接(或内核轮询)实现并发利用 CPU,并可通过 IPC 进行通信与管理。
pipe 原理是怎样的 在 Node/UNIX 中 pipe 将一个进程/流的输出作为另一个的输入,实现流式数据传输。Node 中 stream.pipe 将可读流的数据写入可写流,处理 backpressure(返回 false 时暂停读取,待 drain 恢复)。
node 的异常处理方式 同步用 try/catch 捕获;异步(Promise)用 .catch 或 async/await + try/catch;对于未捕获异常可用 process.on('uncaughtException') 或 process.on('unhandledRejection') 做最后的日志/降级,但建议优雅重启。
适配器和外观模式的区别 适配器(Adapter)用于把一个接口转换为另一个接口以便兼容,关注接口转换;外观(Facade)提供简化的统一接口屏蔽子系统复杂性,关注简化使用。两者都封装但目的不同。
重构的手段有哪些 常见手段:提炼函数/变量、抽象重复逻辑、拆分模块、引入设计模式、降低耦合、提高内聚、重命名增强可读性、添加测试、持续小步提交与回归验证。
数组去重 常用方法:利用 Set(Array.from(new Set(arr)) 或 [...new Set(arr)]);对象/Map 哈希法用于复杂类型;排序后两端去重;保持顺序并处理对象引用可用 JSON/key map 或深比较。
你比较擅长哪一块,不足的地方在哪里 (此题需你本人回答,示例模板)擅长:前端工程化、React/Vue 框架与性能优化、前端网络与调试。不足:后端系统设计或某些低级系统编程细节(正在通过实践与阅读补足)。

# 回答

# Node

# 1. 模块机制

核心要点

  • CommonJS 规范:每个文件是一个模块,通过 require 导入,module.exports/exports 导出
  • 模块类型
    • 核心模块(内置模块,如 fs, http
    • 文件模块(用户自定义模块)
    • 第三方模块(node_modules
  • 加载过程
    1. 路径解析(优先缓存 → 核心模块 → 路径查找)
    2. 文件定位(自动补全 .js, .json, .node 扩展名)
    3. 编译执行(不同扩展名使用不同编译器)
    4. 加入缓存(require.cache

示例

// 查找顺序示例
require('http') → 核心模块
require('./mod') → 当前目录的 mod.js
require('lodash') → node_modules/lodash

# 2. require 原理

执行流程

  1. 解析路径为绝对路径
  2. 检查 require.cache 是否存在缓存
  3. 创建 Module 实例(包含 exports, id, loaded 等属性)
  4. 根据文件类型加载:
    • .js:包裹成函数 (function(exports, require, module, __filename, __dirname) { ... })
    • .json:直接解析为 JSON.parse
  5. 执行模块代码,填充 exports 对象
  6. 返回 module.exports

关键特性

  • 同步加载
  • 缓存机制(相同模块只加载一次)
  • 循环依赖处理(未完成的 exports 会被提前暴露)

# 3. 事件循环

六个阶段(libuv 实现)

  1. Timers:执行 setTimeout/setInterval 回调
  2. Pending callbacks:执行系统操作回调(如 TCP 错误)
  3. Idle/Prepare:内部使用
  4. Poll
    • 检索新的 I/O 事件
    • 执行 I/O 相关回调
    • 阻塞在此阶段等待新事件(当没有 check 阶段的回调时)
  5. Check:执行 setImmediate 回调
  6. Close callbacks:执行关闭事件回调(如 socket.on('close')

关键要点

  • process.nextTick 在阶段切换前执行(微任务)
  • setImmediate 在 Check 阶段执行
  • I/O 回调在 Poll 阶段执行

# 4. Cluster 原理

核心机制

  • Master 进程通过 cluster.fork() 创建 Worker 进程
  • 共享服务器端口(底层使用 round-robin 负载均衡)
  • IPC 通信通道(通过 process.sendmessage 事件)

代码示例

const cluster = require('cluster')
if (cluster.isMaster) {
  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork()
  }
} else {
  // Worker 代码
  http.createServer().listen(3000)
}

优化策略

  • 心跳检测(防止 Worker 僵死)
  • 优雅重启(disconnect + exit 事件配合)

# 5. 流机制

四种流类型

类型 特性 示例
Readable 数据生产 文件读取流
Writable 数据消费 HTTP 响应
Duplex 双向流 TCP socket
Transform 数据转换 Gzip 压缩

关键概念

  • 背压(Backpressure):通过 highWaterMark 控制缓冲区大小
  • 流动模式data 事件驱动
  • 暂停模式read() 方法手动控制

# 6. pipe 原理

核心实现

readable.pipe(writable) = {
  readable.on('data', (chunk) => {
    if (!writable.write(chunk)) {
      readable.pause();
    }
  });
  writable.on('drain', () => {
    readable.resume();
  });
}

特性

  • 自动处理背压
  • 错误传播(需手动处理)
  • 可链式调用(a.pipe(b).pipe(c)

# 7. 守护进程

创建步骤

  1. 创建子进程
  2. 脱离控制终端(setsid
  3. 改变工作目录
  4. 重定向标准 I/O
  5. 错误处理与日志记录

代码示例

const spawn = require('child_process').spawn
const daemon = spawn(process.argv[0], ['app.js'], {
  detached: true,
  stdio: 'ignore'
})
daemon.unref()

# 8. 进程通信

通信方式

方式 适用场景
管道(pipe) 父子进程间简单通信
消息队列 跨机器通信
共享内存 大数据量传输
Socket 网络通信
Signal 进程控制

Node.js 实现

  • child_process 使用 IPC 通道
  • worker.send()process.on('message')
  • 底层基于 libuv 的跨平台实现(Unix domain socket / Windows named pipe)

# 9. 异常处理

分层处理策略

  1. Try/Catch:同步代码
  2. Promise.catch:异步代码
  3. EventEmitter 错误事件
    const stream = createReadStream('file')
    stream.on('error', (err) => {
      /* 处理错误 */
    })
    
  4. 进程级捕获
    process.on('uncaughtException', (err) => {
      logger.error(err)
      process.exit(1)
    })
    

最佳实践

  • 避免阻塞在 uncaughtException
  • 使用 domain 模块(已废弃,仅旧项目使用)
  • 结合 PM2 等进程管理器实现自动重启

# 总结回答示例

"Node.js 的模块机制基于 CommonJS 规范,通过 require 实现依赖加载,其核心原理包括路径解析、缓存和函数包裹。事件循环分为六个阶段,理解 timers、poll 和 check 阶段的执行顺序至关重要。Cluster 模块通过主进程管理多个 Worker 实现了多核利用,底层使用 IPC 通信。流机制通过背压控制优化了大数据处理性能,pipe 方法则封装了流对接的细节。守护进程需要处理进程分离和日志管理,异常处理要分层级覆盖同步/异步场景。这些机制共同支撑了 Node.js 的高性能服务能力。"

# 参考