-
一个图省事用 any 接住的 JSON 数据,像墨水一样把后面一整片代码的类型检查都染没了,拼错的属性名 TS 一声不吭:一次 any 扩散的深度复盘
从 JSON.parse 拿数据图省事声明成 any,后面把 nickname 拼成了 nikename、用错类型,TS 编译却一个错都没报,上线后取到 undefined 页面空白。根因是 any 关闭对这个值的类型检查(任何操作都放行)且会传染:data 是 any,data.user、data.user.profile 派生的还是 any,从那个 any 开始后面一整片代码都悄悄失去了类型检…- 0
- 0
-
一个把对象方法直接作为回调传给 setTimeout 的写法,执行时 this 变成了 undefined、访问 this 的属性全报错:一次 JavaScript this 绑定丢失的深度复盘
把对象的方法 handleClick(里面用了 this.count)作为回调传给 setTimeout,执行时报 Cannot read properties of undefined——this 居然是 undefined。根因是 JS 的 this 不由'函数在哪定义'决定、而由'如何被调用'决定:setTimeout(obj.fn) 只是把函数本身取…- 0
- 0
-
一个用联合类型加 switch 处理多种形状的函数,在我新增了一种类型后悄悄漏掉了它、TS 却一声不吭,直到线上才暴露:一次 TypeScript 穷尽检查缺失的深度复盘
给图形联合类型加了三角形,在类型定义和创建处都改了、自信上线,结果三角形面积算错。排查发现那个算面积的 switch 忘了加 triangle 的 case、走了 default 返回 0,而 TS 编译全程一声不吭。根因是 TS 默认不对联合类型做穷尽性检查——一个 switch 漏处理某成员它不报错,加新成员后漏改的地方静默遗漏,我对 TS'改类型自动揪出要改处'的期待落空…- 0
- 0
-
一个在 forEach 回调里写 await 的批处理脚本,以为会一个个等着处理完,结果还没处理完就往下走、还吞掉了异常:一次 JavaScript 异步遍历的深度复盘
数据迁移脚本用 forEach 遍历、在回调里 await 逐条同步,处理完打印'全部同步完成'。结果那句几乎立刻就打印了(其实没同步完),而且某条失败抛的异常外层 try-catch 一个都没抓到、变成了 UnhandledPromiseRejection。根因是 Array.prototype.forEach 是同步遍历、完全忽略回调返回的 Promise、不会等待 awa…- 4
- 0
-
一个把数字枚举的值直接存进数据库的设计,在我往枚举中间插了一个新成员后,让所有历史订单的状态集体错位了一格:一次 TypeScript 枚举持久化的深度复盘
订单状态用 TS 数字枚举、状态值以数字存库。某次在'待支付'和'已支付'间插了个'支付中',发布后大量历史订单状态集体往后错位一格——已发货显示成已支付。根因是 TS 数字枚举不显式赋值时值从 0 自动递增、靠声明顺序决定,往中间插成员让后面所有值 +1,而数据库里历史数据存的旧数字没变、代码却用新枚举去解释,含义被悄悄换掉。本文讲透数…- 0
- 0
-
一个直接调用数组 sort() 给价格排序的写法,把 10 排到了 2 前面,让整个排行榜的顺序彻底乱掉:一次 JavaScript 默认排序规则的深度复盘
价格从低到高的列表,顺序却是 1,10,100,11,2,21,3——10 排在了 2 前面。根因是 JavaScript 的 Array.prototype.sort() 不传比较函数时,默认把元素转成字符串、按 Unicode 码位(字典序)比较,而非按数值:'10' 的首字符 '1' 小于 '2',于是 10 排到 2 前面。它在个…- 0
- 0
-
一个用 as User 把后端返回的 JSON 强转成类型的写法,在字段结构对不上时让 TypeScript 的类型检查彻底成了摆设、运行时崩在 undefined 上:一次类型断言滥用的深度复盘
用户详情页在某些用户身上稳定白屏,报 Cannot read properties of undefined——可代码明明有完整类型声明、编译一个错没报。根因是 const user = await res.json() as User:as 只是类型断言,在编译期单方面告诉编译器'信我这是 User',不做任何运行时检查或转换;后端某些情况没返回 profile,TS 毫不知…- 2
- 0
-
我发布了前端新版本,可一大批用户死活还是旧页面、改的 bug 在他们那儿没修复,我对着 HTTP 缓存的 Cache-Control 排查了大半天的复盘
修了个前端 bug,打包发布上线,自己刷新好了。可没多久客服炸了:一大批用户那个 bug 还在、页面还是旧的,让他们刷新有的也没用,直到清缓存/强制刷新才好。困惑——我明明发了新版本服务器都是新代码,用户怎么还用旧的?排查大半天才理解 HTTP 缓存的门道和我没配好 Cache-Control 的疏忽:我给所有静态资源配了超长强缓存 max-age=1年、而 js/css 文件名又是固定的(app…- 0
- 0
-
我把对象的方法直接传给 setTimeout 当回调,运行到一半就报 this 是 undefined,我对着 JavaScript 的 this 指向丢失排查了大半天的复盘
用原生 JavaScript 写小组件,有个类的方法负责更新状态,我把它当回调传给了 setTimeout 和按钮事件监听,读起来天经地义。一运行控制台就炸:Cannot read properties of undefined,报错在方法内部 this.state 那行。懵了:方法明明是这对象的,this 不就该是它吗?排查大半天才理解 JS 里让无数人栽跟头的概念:this 的指向不取决于方法…- 0
- 0
-
商品按价格排序,9 块钱排在了 80 块后面:我在 JavaScript 里被 Array.sort() 默认按字符串排序坑惨的那次线上事故复盘
商品列表"按价格从低到高"排序,上线后却乱成一团:9 元排在 80 元后面,1000 元跑到 200 元前面。控制台一跑 [9,80,100,1000,200].sort() 得到 [100,1000,200,80,9]——真凶是 Array.sort() 不传比较函数时,默认把元素转成字符串、按字典序排,"100"- 0
- 0
-
给五个按钮绑点击事件,点哪个都弹出"第 5 个":我在 JavaScript 里被一个 for 循环里的 var 闭包坑到怀疑人生,以及作用域与闭包的全面复盘
动态生成五个按钮,点第几个就弹"第几个"——结果点哪个都弹"第 5 个"。绑定时打印 i 明明是 0~4,执行时却全变 5。根因是 var 函数作用域:整个循环只有一个 i,而五个闭包捕获的是这个变量的引用而非值。这篇复盘讲清原理、let 一字之差的正解、IIFE 等老办法,并延伸到 setTimeout 异步亲戚坑,以及闭包既是坑也是 JavaScript…- 0
- 0
-
同一个方法自己调好好的、一传给 setTimeout 或事件监听当回调就报 this 是 undefined:JavaScript this 绑定丢失的避坑复盘
这是一个让我对 JavaScript 的 this 彻底改观的 bug,也是几乎每个 JS 开发者都会踩一次的成人礼。事情是这样的:我写了一个类里面有个方法 handleClick,方法里要用到这个类实例的一些数据比如 this.state。开发时我直接调用 instance.handleClick 一切正常,可当我把这个方法作为回调函数传出去,比如绑给一个按钮的点击事件或者塞进一个 setTim…- 0
- 0
-
联合类型新增了一种成员却忘了在 switch 里加 case,编译一声不吭这类消息全悄悄丢了:TypeScript 穷尽性检查避坑复盘
这是一个加了功能旧功能却悄悄漏了的事故,而且漏得无声无息直到用户反馈才发现。我们有一个消息处理器负责处理几种类型的消息用一个联合类型定义,用一个 switch 分门别类地处理它们。某次需求产品要新增一种消息类型,我很自然地在那个联合类型的定义里加上了新类型然后改了相关逻辑,编译通过测试我新加的功能也正常就上线了。可上线后陆续有用户反馈某一类消息没反应像石沉大海,排查半天才发现:我新增了消息类型却忘…- 3
- 0
-
插个枚举值搞乱所有历史数据:TS 数字枚举避坑复盘
这是一个改了一行无害的代码却让历史数据集体错乱的诡异事故,排查时让我惊出一身冷汗。起因小到不能再小:产品要在订单状态里新增一个待审核的状态,我们的订单状态是用 TypeScript 的枚举定义的,我很自然地把这个新状态插进了枚举中间一个语义上最合适的位置,改完测试新功能一切正常就上线了。可第二天客服那边就炸了:大量用户反馈自己历史订单的状态显示全乱了,明明早就已完成的订单变成了已取消,数据像被恶意…- 0
- 0
-
tsc 全绿生产却白屏:TypeScript as 断言避坑复盘
一次很普通的发版,前端没怎么动,主要是后端调了几个接口,可发版后没几分钟客服群就炸了:页面整片白屏。打开 Sentry 满屏密密麻麻同一个错误——Cannot read properties of undefined。最让我懵的是,这套代码是 TypeScript 写的,tsc 编译零报错,本地和测试环境一切正常,CI 全绿才放出去的,一个号称类型安全的项目怎么会因为读取 undefined 属性…- 0
- 0
-
方法当回调 this 就丢:JS this 指向避坑复盘
有个 JavaScript 的类里有个方法,逻辑是处理点击事件然后更新自己的一个属性:class Counter { count = 0; handleClick() { this.count++ } },然后我把这方法当回调绑到按钮上 button.addEventListener(click, counter.handleClick)。本地一测点击按钮啪一声控制台红字:Cannot read …- 0
- 0
-
忘了一个 await:TS 浮动 Promise 乱序吞错避坑
有个用 TypeScript 写的下单流程:扣库存、写订单、再发通知,每步封装成 async 函数主流程里一个个调过去,代码写得很顺。可上线后偶发诡异:有时订单写进去了库存却没扣、有时通知发了订单还没落库,还有一次某步明明内部抛了异常外层 try/catch 却完全没捕获到、错误像人间蒸发既没日志也没告警只留一堆对不上的脏数据。逻辑明明是顺序写的怎么会乱序还吞异常?逐行抠 async 调用才发现真…- 9
- 0
-
购物车总价差一分钱:JS 浮点数精度避坑复盘
有个电商页面的购物车前端用 JavaScript 实时计算总价:单价乘数量再累加显示给用户,功能简单到我都懒得多测就上线了。可没过几天客服转来一个诡异投诉:有用户结算时前端显示的总价和后端最终算出的金额差了一分钱。一分钱不多,可金额对不上在交易系统里就是天大的事,用户截图质问、财务对账报警。我把那个用户的购物车数据捞出来在控制台手动一算当场就笑不出来了:0.1 + 0.2 在 JavaScript…- 0
- 0
-
插一个枚举值搞乱历史数据:TS 数字枚举避坑
有个订单状态我们用 TypeScript 枚举表示:enum OrderStatus { Created, Paid, Shipped, Completed },然后把状态值存进数据库——存的是数字,平稳跑了大半年。直到某次迭代我要在已付款和已发货之间加一个备货中,很自然地把它插在中间,改完测试一切正常便上线。然后客服就炸了:大量用户反馈我明明已收到货订单却显示备货中、我刚下单还没付款怎么显示已发…- 0
- 0
-
所有按钮都触发最后一项:JS 闭包与 var 陷阱
一个再简单不过的需求:页面动态渲染一排按钮,每个对应一条数据,点击弹出你选了第几项。我三下五除二写完,本地点第一个按钮弹出的却是最后一项,点第二个还是最后一项,点哪个通通是最后一项,功能演示当场翻车,而我盯着那段自认为毫无问题的代码百思不得其解。把循环变量打印出来才看清真相:每个按钮的点击回调里拿到的 i 全都是循环结束后的最终值,罪魁祸首是那个我用了无数次从没多想的关键字 var——它声明的 i…- 4
- 0
-
编译全绿线上却白屏:TypeScript 类型安全的错觉
我们的前端是 TypeScript 写的,团队一直引以为豪:有类型保护、编译器把关,线上应该很稳。直到某天一个核心页面在生产环境白屏,控制台赫然一行红字:Cannot read properties of undefined (reading name)。我难以置信——这不正是 TS 该帮我挡住的错误吗?编译一片绿灯、tsc 没报任何问题,怎么还会运行时栽在读取 undefined 的属性上?扒下…- 0
- 0
-
类型全绿却线上白屏:TypeScript 编译期与运行时的鸿沟
那天下午客服群先炸了:一批用户打开个人中心是一片白屏,Sentry 里清一色是 Cannot read properties of undefined。诡异的是本地怎么都复现不出,而项目是全 TypeScript 写的、tsc 编译一个 error 都没有、全绿通过。引以为傲的"类型安全"显得格外讽刺。顺着字段往上扒才发现:后端前一天把某些用户的 profile 字段返回成了 …- 0
- 0
-
页面为什么会卡死:从一个转不起来的 loading 说透 JS 事件循环
有个 bug 报上来时描述特别朴素:点了按钮,页面卡死三四秒,期间界面点不动,转圈的 loading 也不出现,等它缓过来结果直接就显示了。翻代码一看,setLoading(true) 和 setLoading(false) 一个没漏,可 spinner 就是死活不肯露面。根子在一个人人听过却很少想透的事实:JavaScript 是单线程的——那段同步的重循环死死霸占着唯一的线程,浏览器既没机会把…- 2
- 0
-
一个 any 引发的事故:TypeScript 的类型为什么没拦住这个 bug
一个计费接口某天开始把用户金额算成 NaN,客服工单瞬间堆满。诡异的是整个项目是 TypeScript 写的、strict 全程开着、CI 里 tsc 一个 error 都没有,类型系统却眼睁睁放这个 bug 溜进了生产。排查到最后根因小得窝火:上游 API 把字段从 userName 改成 user_name,而我们 fetch 的返回值类型是 any。这篇就从这个类型没拦住的 bug 讲起,把…- 2
- 0
前端
幸运之星正在降临...
点击领取今天的签到奖励!
恭喜!您今天获得了{{mission.data.mission.credit}}积分
我的优惠劵
-
¥优惠劵使用时效:无法使用使用时效:
之前
使用时效:永久有效优惠劵ID:×
没有优惠劵可用!
























