9年前端踩过的10个坑,新手一定要避开(附代码+解决方案)

10 阅读4分钟

做了9年前端,web、app、桌面应用、小程序都做过,踩过的坑比写过的Bug还多。

今天挑10个最高频、最容易踩的坑分享出来,每个坑附完整代码和解决方案。建议收藏,迟早用得上。

坑1:浮点数精度——电商项目的噩梦

// 经典翻车现场
0.1 + 0.2 === 0.3  // false

// 实际项目中的坑
const price = 19.9
const qty = 3
console.log(price * qty) // 59.699999999999996

解决:金额场景统一用「分」为单位,整数运算。前端展示时 (amount / 100).toFixed(2)

// 正确做法
const priceInCent = 1990
const total = priceInCent * 3  // 5970
const display = (total / 100).toFixed(2)  // "59.70"

坑2:Vue3 reactive解构丢失响应式

// ❌ 响应式丢了
const state = reactive({ count: 0, name: 'test' })
const { count, name } = state  // 普通变量,不再响应式

// ✅ 用toRefs
const { count, name } = toRefs(state)

// ✅ 更推荐直接用ref
const count = ref(0)

这个坑我亲眼见过3个项目踩了,页面不更新,排查半天,结果是解构问题。

坑3:useEffect依赖遗漏(React闭包陷阱)

// ❌ count永远是0
const [count, setCount] = useState(0)
useEffect(() => {
  const timer = setInterval(() => {
    console.log(count)  // 闭包捕获了初始值0
  }, 1000)
  return () => clearInterval(timer)
}, [])  // 空依赖

// ✅ 用函数式更新
useEffect(() => {
  const timer = setInterval(() => {
    setCount(prev => prev + 1)
  }, 1000)
  return () => clearInterval(timer)
}, [])

坑4:addEventListener不移除——内存泄漏

// ❌ 组件卸载后监听器还在
mounted() {
  window.addEventListener('resize', this.handleResize)
}
// 忘了在destroyed/unmounted里移除

// ✅ Vue3正确做法
onMounted(() => {
  window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})

一个项目里有5个组件各加了scroll监听不移除,页面越来越卡,排查了一下午。

坑5:flex布局下text-overflow失效

/* ❌ 省略号不生效 */
.flex-item {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ✅ 加min-width: 0 */
.flex-item {
  min-width: 0;  /* flex子元素必须加这个 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

这个坑不知道害了多少人,flex子元素默认min-width是auto,不会缩小到比内容小。

坑6:深拷贝的隐藏Bug

// ❌ JSON.parse(JSON.stringify()) 的坑
const obj = {
  date: new Date(),     // 变字符串
  fn: () => {},         // 丢失
  undef: undefined,     // 丢失
  reg: /test/,          // 变空对象
}

// ✅ 用structuredClone(2022+原生支持)
const copy = structuredClone(obj)
// 注:函数仍然无法拷贝,需要手动处理

坑7:小程序setData传大数据——页面卡死

// ❌ 一次传500条列表数据
this.setData({ list: hugeArray })

// ✅ 分页加载 + 路径更新
this.setData({
  [`list[${index}].status`]: 'done'  // 只更新变化字段
})

setData是跨线程通信,数据量大直接卡死。做过一个电商小程序,首页列表300条商品,setData一次耗时200ms+,改成路径更新后降到3ms。

坑8:路由懒加载没做——首屏白屏5秒

// ❌ 同步导入所有页面
import Home from './pages/Home'
import User from './pages/User'
import Order from './pages/Order'

// ✅ 路由懒加载
const routes = [
  { path: '/', component: () => import('./pages/Home.vue') },
  { path: '/user', component: () => import('./pages/User.vue') },
]

一个后台项目30多个页面全同步加载,打包后vendor.js有2MB,首屏白屏5秒。加了懒加载后1.2秒。

坑9:环境变量泄露——密钥暴露在前端

// ❌ 把API密钥写在前端代码里
const API_KEY = 'sk-xxxxxxxxxx'  // 打包后源码可见!

// ✅ Vite项目只有VITE_前缀的才暴露
// .env
VITE_API_URL=https://api.xxx.com  // ✅ 可暴露
SECRET_KEY=sk-xxx                  // ✅ 不会暴露

见过一个项目把支付密钥写在前端config里,上线2天被薅了3万。

坑10:跨域问题——开发能用上线就挂

// ❌ 开发环境直连API
fetch('http://api.xxx.com/data')

// ✅ 开发用proxy,生产用nginx反向代理
// vite.config.js
server: {
  proxy: {
    '/api': {
      target: 'http://api.xxx.com',
      changeOrigin: true,
      rewrite: path => path.replace(/^\/api/, '')
    }
  }
}

每个前端新人都会踩一次跨域的坑,区别只是踩早踩晚。

总结

排名坑点严重度
1浮点数精度⭐⭐⭐⭐⭐
2Vue3响应式丢失⭐⭐⭐⭐⭐
3useEffect闭包⭐⭐⭐⭐⭐
4事件监听泄漏⭐⭐⭐⭐
5flex省略号失效⭐⭐⭐⭐
6深拷贝Bug⭐⭐⭐
7setData传大数据⭐⭐⭐⭐⭐
8首屏白屏⭐⭐⭐⭐⭐
9环境变量泄露⭐⭐⭐⭐⭐
10跨域问题⭐⭐⭐⭐

这些坑我用9年经验帮你踩过了,收藏备用,遇到的时候能省你几个小时调试时间。

评论区说说你踩过最坑的前端Bug是什么?


我是前端老兵AI,9年+前端工程师,专注前端实战+AI编程提效

📦 加微信lxxs1203,备注"掘金",领取《前端+AI编程实战干货包》

🎬 更多实操视频 → B站搜索:前端老兵AI

📱 公众号搜索「前端老兵之AI」,持续更新深度技术文章