面试备战录

115 阅读5分钟

1、npm run dev做了什么

答:在前端项目中,npm run dev并不是Node自带的命令,而是调用package.json中定义的scripts脚本,通常用来启动开发环境。它的具体行为取决于你使用的工具链(如Vite、Webpack、Next.js、React Scripts等)。

具体执行的事情:

  • 启动开发服务器
    • 本地开启一个 HTTP服务,通常监听 localhost:30005173
    • 支持热更新(HMR),修改代码后浏览器自动刷新或更新页面。
  • 构建/编译源代码
    • JSX/TS/ES6+代码编译成浏览器可执行的 JS(Babel、esbuild 或 SWC)
    • 处理 CSS、Sass、Less、PostCSS、图片等资源。
  • 生成模块依赖图
    • 解析import/export,打包模块,形成依赖关系树。
  • 启动热模块替换 (HMR)
    • 监听源文件变化,修改对应模块时只更新变化部分,避免全量刷新。
  • 提供Source Map
    • 方便调试,让浏览器调试器能显示源码而不是打包后的代码。

npm run dev 是前端开发环境的启动命令,负责编译、打包、启动本地服务、提供热更新,让你可以在本地调试项目。

2、用到的打包工具有什么区别,为什么vitewebpack

答:前端常用的打包工具有

  • Webpack:老牌工具,功能最强大,生态丰富。采用基于配置的打包思路,所有文件先打包再交给浏览器。
  • Rollup:偏向库打包(比如Vue/React官方库都用它),支持Tree Shaking更彻底,但对多页应用支持一般。
  • Parcel:零配置上手快,内置很多功能,但扩展性比Webpack差。
  • Vite:新一代构建工具,利用浏览器原生ES Modules,开发环境快如闪电,生产模式下内部用Rollup打包。

WebpackVite 的区别在于:

  • 开发环境的区别
  • Webpack
    • 启动时需要把所有依赖文件打包好,再启动开发服务器。
    • 项目大时启动慢(可能要十几秒甚至更久)。
  • Vite
    • 不打包整个项目,而是直接利用 浏览器原生 ES Module (<script type="module">)
    • 只有在页面请求某个模块时,才会用esbuild(超快的 Go 语言编写的工具)做按需编译。
    • 启动项目几乎是秒开
  • 依赖预构建
    • Vite启动时会用esbuild把依赖(如React、lodash等第三方包)转为高效的ES Module格式,之后直接走缓存。
    • Webpack每次启动都要重新构建依赖,速度更慢。
  • HMR(热更新)的区别
    • Webpack:更新某个文件后,要重新构建依赖图中相关的模块,更新速度会越来越慢。
    • Vite:直接让浏览器重新请求被修改的模块,天然按需,更新速度恒定。
  • 生产环境的区别
    • Vite开发环境用esbuild,生产环境依然用Rollup打包(保证稳定和优化能力)。
    • Webpack 一直用自己的打包逻辑。
  • 适用场景
    • Webpack:适合大型企业项目,生态完善,插件丰富,复杂场景(比如微前端、定制 loader)依然强大。
    • Vite:适合现代Web项目、组件库开发、快速迭代的应用。前端新项目大多首选Vite

3、你能说说Vue3是如何追踪依赖并触发更新的吗?

答:Vue3的响应式机制是Proxy + effect 追踪依赖来实现自动更新。

  • 响应式对象的创建,Vue3使用reactiveref创建响应式数据:
    • reactive会返回一个Proxy,拦截对象的 读/写操作。
    • ref是对基本类型值的包装,也会生成一个对象,内部通过getter/setter实现追踪。
  • 依赖收集(依赖追踪)
    • Vue内部维护一个全局活动 effect(称为activeEffect
    • 模板computedwatchEffect 中访问响应式数据时:
      • Proxyget拦截器被触发
      • Vue会将当前activeEffect注册到这个属性对应的依赖集合(Dep)
  • 触发更新(响应式变化)
    • 当你修改响应式数据时:
    • Proxyset拦截器被触发
    • Vue会找到 这个属性对应的依赖集合,将里面的effect都调度执行
    • 如果effect是组件渲染函数,就会重新渲染组件

特性:

  • 按需追踪:只追踪真正使用的数据,不使用的数据不会触发更新
  • 嵌套响应式:Proxy会递归创建深层对象响应式
  • 自动清理:effect执行前,Vue会清理之前依赖,避免重复收集

4、React中为什么useEffect有时会导致闭包问题?你是如何避免的?

问题:闭包捕获旧值

function Counter(){
 const [count, setCount] = useState(0);
 useEffect(()=>{
     const id = setInterval(() => {
        console.log(count); // ⚠️ 每次都是闭包里的旧 count
        setCount(count + 1);
      }, 1000);
     return () => clearInterval(id);  
 },[])
}
  • useEffect 的回调函数在 初次渲染时就被创建
  • 闭包捕获了当时的count = 0
  • 所以 setInterval 内的 count 永远是 0 → 闭包陷阱
  • 导致计数器不会累加如预期
  • useEffect闭包只会捕获它创建时的作用域变量
  • 如果依赖数组不包含某个state/prop ,闭包里的值就不会更新
  • 这是React的渲染和闭包机制导致的

解决办法:

  • 把依赖加到依赖数组,但每次都会重新清除并创建新的setInterval,
  • 使用函数式更新 setCount(prev => prev + 1);,setState 内部可以获取到最新的state,而不是闭包里的旧值