tree shakeing

摇树是怎么实现的

  • Tree Shaking 实现关键是:*ES6 (es module)模块是 “静态” 的
  • 打包工具从「入口文件」开始遍历所有代码,标记死代码并删掉

组件库按需加载

  • 打包插件实现将默认的import方式,转成组件的 JS、CSS 分别import的写法

ESM 转 CJS

  • 本质是替换import/exportrequire/module.exports
  •  Babel/Rollup为转换常用工具

webpack

loader 和 plugin 的区别

  • Loader 管「文件转换」:微观处理单个文件,让 Webpack 能识别非 JS/JSON 文件;如
    1. css-loader:解析 .css 文件里的 @importurl(),把 CSS 转成 Webpack 能识别的模块;
    2. style-loader:把 css-loader 处理后的 CSS 注入到 HTML 的 <style> 标签里;
    3. babel-loader:把 ES6+ 语法的 JS 转成 ES5,兼容老浏览器;
    4. ts-loader:把 TypeScript 代码转成普通 JS;
    5. file-loader:处理图片 / 字体等静态资源,输出到指定目录并返回文件路径。
  • Plugin 管「流程扩展」:宏观控制打包全流程,实现各种自动化、优化功能。比如压缩代码、生成 HTML

plugin 的实现原理(node 的 eventbus 模块,发布订阅)

定义一个具有 apply 方法的 prototype 对象,里面会有一个hook对象可以对webpack事件进行监听控制,进而控制打包流程

图片懒加载原理

本质:页面滚动时,只有图片快进入屏幕可视区域了,才加载这张图片
一开始加载缩略图,真实图片url放在data-src属性里,监听滚动事件,待页面滚动到图片进入屏幕可视区域,替换真实属性加载图片
优化:

  • 滚动事件频繁触发需要加防抖,
  • 不用监听滚动事件,使用IntersectionObserver现代api,自动判断元素是否进入视野

虚拟列表原理

本质:只渲染可视区域的列表项,用占位容器撑出总高度,滚动时只替换可视区的内容和位置

简单说一下vite和webpack区别

维度WebpackVite
启动速度慢(项目越大越慢)

原因:启动时要遍历、打包所有代码,生成 bundle 文件
极快(毫秒级)

原因:不打包,直接用 ESM,只处理入口文件,按需编译
热更新速度慢(改代码后要重新打包相关模块)快(只编译修改的文件,不用动其他代码)
构建思路「打包优先」

不管代码是否用到,先打包成兼容所有环境的 bundle
「按需编译」

开发环境不打包,生产环境用 Rollup 轻量打包(体积更优)
底层工具自身处理模块编译(比如 babel 处理 ES6+)开发环境用 esbuild(Go 语言写的,编译速度是 babel 的几十倍),生产环境用 Rollup
兼容场景全能(支持老项目、CommonJS/ESM、各种复杂配置)主打现代前端(只支持 ESM,老项目 / CommonJS 需适配,配置更简洁)
使用成本配置复杂(loader/plugin 多,需手动配)配置极简(内置大部分常用功能,比如 Vue/React/TS 开箱即用)
总结
Webpack 是「先打包再运行」,适配全场景但慢;Vite 是「不打包直接运行,按需编译」,只适配现代环境但极快。

计算机网络

类比 “快递运输流程”,每层只干自己的活,层层配合:

  1. 物理层:最底层(网线、光纤、网卡),负责 “传电信号 / 光信号”(比如快递的 “运输路线,如公路、铁路”);
  2. 数据链路层:负责 “相邻设备通信”(比如路由器和电脑之间的连接,像 “快递站点之间的短途运输”);
  3. 网络层:负责 “跨网段找路”(比如从北京到上海的快递路由,核心是 IP 地址,像 “快递的全国路由规划”);
  4. 传输层:负责 “端到端通信控制”(TCP/UDP 在这里,像 “快递的运输方式:普通快递 / TNT 加急”);
  5. 会话层:负责 “建立 / 维持 / 断开通信会话”(比如登录网站时的连接会话,像 “快递员和收件人确认收货”);
  6. 表示层:负责 “数据格式转换”(比如加密、压缩、编码,像 “快递包裹的包装 / 拆包”);
  7. 应用层:最顶层(用户直接用的),负责 “提供应用服务”(比如 HTTP、FTP、微信,像 “用户下单 / 收件的操作”)。

记忆口诀:物数网传会表应(从下到上,记首字)。

2. TCP 和 UDP 的区别(通俗类比:打电话 vs 发短信)
对比维度TCP(打电话)UDP(发短信)
连接要求必须先建立连接(三次握手),像打电话要等对方接无连接,直接发,像发短信不用等回复
可靠性可靠(丢包重传、按序到达),像打电话能确认对方听到不可靠(丢包不重传、无序),像发短信可能丢件 / 乱序
速度慢(要确认、重传)快(无额外开销)
适用场景需可靠传输的(网页、文件下载、登录)需高速实时的(视频通话、直播、游戏)

记忆要点:TCP 重可靠(连、稳、慢),UDP 重速度(无连、快、糙)。

3. TCP 和 UDP 属于哪一层?

属于 传输层(七层模型的第 4 层)。核心作用:在网络层(IP 找路)的基础上,给应用层提供 “端到端的通信服务”(比如区分同一设备上的不同应用,靠端口号,像快递到小区后,区分不同住户)。

面试总结(直接背)
  1. 七层模型:物数网传会表应,从下到上,每层负责不同通信环节;
  2. TCP vs UDP:TCP 连、稳、慢(网页 / 文件),UDP 无连、快、糙(直播 / 游戏);
  3. 所属层级:两者都在传输层,负责端到端通信控制。

闭包是什么

核心定义(一句话):

闭包就是内层函数能访问外层函数的变量,且外层函数执行完后,这些变量不会被销毁

面试记忆要点:
  1. 本质:函数嵌套 + 变量跨作用域访问;
  2. 关键:外层函数执行后,变量不销毁(常驻内存);
  3. 用途:保存变量(如防抖 / 节流)、私有化变量(避免全局污染);
  4. 注意:滥用会内存泄漏(变量一直占内存,需手动释放)。
极简例子(辅助理解):
function outer() {
  let num = 1; // 外层变量
  return function inner() { // 内层函数(闭包)
    console.log(num); // 能访问num,且outer执行完num不销毁
  };
}
const fn = outer();
fn(); // 打印1(闭包生效)

在react 里函数闭包下如果更新状态,可能会遇到什么问题?怎么解决

React 函数组件中,闭包会捕获当前渲染时的状态值,如果在异步操作(如 setTimeout、事件监听、网络请求)里访问状态,拿到的是「旧状态」,而非最新的状态 —— 因为闭包保存的是当时渲染的状态,后续状态更新触发新渲染,但旧闭包仍指向旧值
解决:

  • 函数式更新(最推荐,适配状态更新场景)
  • useRef 存最新值(适配「读取最新状态」场景)
  • 清理副作用(避免旧闭包生效)