-
我在 JavaScript 里随手用一个普通对象当字典来存用户提交的键值数据还用 key in obj 判断某个键存在不存在,结果有用户根本没提交过 toString 这个键我的代码却判定它存在并走错了分支,更有个用户把键填成 __proto__ 直接让一批对象行为错乱,排查很久才搞懂用字面量对象当字典时它身上本就继承着一堆原型链上的属性的深度复盘
我做一个功能要把用户提交的一批键值对(键是用户填的字段名值是内容)存起来再做判断,图省事直接用普通对象 {} 当字典:const dict={}; dict[key]=value,判断键在不在用 if(key in dict)。开发拿正常数据测都好,可上线后冒出邪门事:有分支是 if(key in dict),结果用户从没提交过 toString 这个键、可 'toString'…- 0
- 0
-
我在 JavaScript 里把一个字符串数组用 map 直接交给 parseInt 想批量转成数字、写法简洁我很满意,结果转出来是 1、NaN、NaN 一片狼藉,我盯着这行干净利落的代码百思不得其解,最后才搞懂 map 会偷偷给回调塞三个参数而 parseInt 把其中那个下标当成了进制的深度复盘
我有一个字符串数组 [1,2,3](字符串),想批量转成数字,觉得最优雅是 arr.map(parseInt)——把 parseInt 直接当回调传给 map,简洁 point-free。满以为得到 [1,2,3],结果是 [1,NaN,NaN]:第一个对后面全是 NaN。我反复确认数组就是三个正常数字字符串、parseInt("2") 单独调明明是 2。直到查 map 给回调…- 3
- 0
-
我在 JavaScript 里用 reduce 求和写得简洁又顺手、测试也全过,上线后却突然抛出 Reduce of empty array with no initial value 把页面整个搞崩,我盯着那行用了无数次的 reduce 百思不得其解最后才明白只要传进来的是个空数组而我又没给它一个初始值 reduce 就会因为根本没有起点可用而直接报错的深度复盘
我有段代码要把数组里的数字求和(或把一批对象的某字段累加),很自然写成 items.reduce((sum, item) => sum + item.amount),本地测写单测传的都是有数据的数组、一切正常结果也对,放心上线了。可线上某个场景下 items 是个空数组(用户没订单、筛选后没结果),整个页面崩了、控制台一行 TypeError: Reduce of empty array w…- 0
- 0
-
我在 JavaScript 里写了 const sorted = list.sort() 想拿到一个排好序的新数组、同时保留原始顺序的 list 去做别的事,结果后面所有依赖原始顺序的逻辑全乱了套,排查很久才发现 sort 根本不返回新数组、它是把原来的 list 就地排序了我那两个变量指向的压根是同一个被改过的数组的深度复盘
我有个数组 list 代表用户提交的有意义的原始顺序,需要两份东西:一份按金额排序后展示、一份保持原始顺序做第 N 条对应第 N 个录入的对应关系。我顺手写下 const sorted = list.sort((a,b)=>a.amount-b.amount),以为 sorted 是排序后的新数组、list 还是原来的样子。可后面用 list 做对应关系时全错位了,打印 list 才傻眼——…- 0
- 0
-
我想快速造一个长度为 5、每项都初始化好的数组,顺手写了 new Array(5).map,结果 map 里的函数一次都没执行、拿到的还是一个全是空的数组,排查半天才发现 new Array(5) 造出来的根本不是 5 个 undefined、而是 5 个会被 map 跳过的空位的深度复盘
我想快速生成一个长度 5、每项都初始化好的数组,很自然写了 new Array(5).map((_, i) => i),在脑子里这就是造 5 个格子再逐个填值。可结果让我懵了:map 里的函数一次都没执行(加 console.log 一行都没打印),拿到的还是个长度 5 却什么都没填的空数组。我以为 map 用错了、箭头函数写错了,检查语法都没问题。直到把 new Array(5) 打印出来…- 0
- 0
-
我拿到一堆 DOM 元素,顺手对它调用 map 想批量处理,结果浏览器甩给我一句 xxx.map is not a function,可它明明有 length、能用下标访问、看着就是个数组,排查半天才发现它只是个长得像数组的类数组对象的深度复盘
我用 document.querySelectorAll 拿到页面上一批元素,想批量处理就写了 elements.map,在我脑子里这就是个装着 DOM 元素的数组。可一运行浏览器直接报错 elements.map is not a function。我当场懵了:这玩意儿明明有 length、能用 elements[0] 下标访问、能 for 遍历、打印出来也是方括号包着一串元素,怎么看怎么是数组…- 0
- 0
-
我在 JavaScript 里想用对象当键,给每个对象存一份关联数据,结果不管存多少个不同的对象,它们竟全都覆盖到了同一个键上、互相把数据冲掉,排查半天发现对象当普通对象的键时会被悄悄转成同一个字符串的深度复盘
我有个需求:给一批对象,每个关联一份额外数据(比如给每个用户对象存一份计算结果)。我很自然地用一个普通对象 {} 当映射表,把对象本身当键、数据当值塞进去,自觉这是再普通不过的对象到数据的映射。可结果完全乱套:我明明存了好几个不同对象的数据,最后表里却只剩一份,不管用哪个对象去取都是最后存进去那份。每个对象明明都是不同实例、地址不一样,怎么会被当成同一个键?直到我把所有键打印出来才整个人不好了:那…- 0
- 0
-
我想判断一个计算结果是不是 NaN,顺手写了 x === NaN,结果它永远返回 false、NaN 一路混了过去到处传播,因为 NaN 是唯一一个连等于它自己都不成立的值的深度复盘
我有段计算,某些异常输入下结果会变成 NaN,我想判断一下是 NaN 就用默认值兜底,写了 if (result === NaN) result = 0。结果完全没生效:result === NaN 永远返回 false,哪怕 result 真的就是 NaN 也拦不住,于是 NaN 一路混过去、参与后续计算又产生新的 NaN、到处传播,最后页面一片 NaN 却定位不到源头。复盘才搞懂:NaN 是一…- 0
- 0
-
我在 JavaScript 里用 setTimeout 0 想让一段逻辑稍后立即执行来排个时序,结果它总是排在所有 Promise 回调的后面执行,输出顺序跟我写的顺序完全对不上,因为微任务永远先于宏任务的深度复盘
我有段逻辑想让它在当前同步代码跑完后尽快执行,用了 setTimeout(fn, 0),以为 0 毫秒就是马上、最先执行。可代码里同时还有 Promise.then 回调,运行结果让我懵了:setTimeout(0) 总是排在所有 Promise.then 回调的后面执行,日志顺序和书写顺序完全对不上,靠它排的时序也错乱。复盘才搞懂:JS 单线程靠事件循环调度异步,异步分宏任务(setTimeou…- 0
- 0
-
我用逻辑或给配置项设默认值,用户明明传了一个合法的 0,却被我当成没传替换成了默认值,因为 || 判断的是假值不是是否缺失,而 0、空字符串、false 都是合法却为假的值的深度复盘
我有个配置项 pageSize,为了用户没配时给默认值 20,写得很顺手:const pageSize = config.pageSize || 20。一直好好的,直到有用户反馈:我把 pageSize 配成了 0(业务里 0 表示不分页、返回全部),系统却还是按 20 分页、我的 0 不生效!一看代码就傻眼:config.pageSize 明明是 0,可 0 || 20 的结果是 20——|| …- 0
- 0
-
我图省事调了个异步函数发通知,既没 await 也没 catch,想着失败了无所谓,结果它一旦 reject 整个 Node 进程就因为未处理的 Promise 拒绝直接崩溃退出:一次 unhandled rejection 拖垮服务的深度复盘
我有个发通知的异步函数 sendNotification(user),心想通知失败也无所谓、不影响主流程,就图省事写成 fire-and-forget:sendNotification(user)——既没 await 也没 .catch(),调完不管。平时风平浪静,直到某次通知下游抽风、它内部的 Promise reject 了,而我没有任何地方处理这个 reject,整个 Node 进程因为 U…- 0
- 0
-
我用 new Date 造了个 6 月 1 日,它却给我变成了 7 月 1 日;后端传来的日期前端显示又差了一天:一次 JavaScript Date 月份从 0 开始与解析时区的深度复盘
我用 JS 的 Date 处理日期出了两件诡异的事:想构造 2026 年 6 月 1 日写了 new Date(2026, 6, 1),打印出来居然是 7 月 1 日;后端传来 '2026-06-02',new Date 解析后展示给用户,有些用户看到的是 6 月 1 日差了一天。查清才明白是 JS Date 的两个经典坑:一是 Date 的月份从 0 开始(0=一月、6=七月…- 0
- 0
-
我用双等号判断年龄是不是 0,结果表单没填(空字符串)的也被判成了 0,因为 JavaScript 的 == 在背后偷偷做了类型转换:一次 JS 宽松相等隐式转换的深度复盘
我有段校验用 if (user.age == 0) 判断年龄是不是 0,功能大体能用,可线上那些根本没填年龄(user.age 是空字符串 '')的用户也被当成了 0 岁、走进了 0 岁的特殊处理。当我看到 '' == 0 在控制台返回 true 时人都傻了。查清才明白:JS 的 ==(宽松相等)在比较两个不同类型的值时,会先偷偷把它们隐式转换(强制类型转换…- 0
- 0
-
我用 JSON.parse(JSON.stringify()) 深拷贝了一个带 Date 的对象,拷贝完调 date.getTime() 直接报错,因为那个 Date 早被悄悄变成了字符串:一次 JS 深拷贝丢失类型、误用流行偏方的深度复盘
我要深拷贝一个配置对象(里面有 createdAt 是 Date、还有些可选字段),用了那个人人都在用、看起来万能的技巧 JSON.parse(JSON.stringify(obj))。一开始好好的,直到某段代码对拷贝出来的对象调 copy.createdAt.getTime()——砰,TypeError: getTime is not a function。打印对比才看明白:这个深拷贝的原理是先…- 0
- 0
-
我把一个对象的方法直接当回调传给了 setTimeout 和事件监听,触发时报 Cannot read properties of undefined:一次 JavaScript this 指向丢失、把方法拆离对象就丢了绑定的深度复盘
我写了个 class 管理面板,把方法 handleClick 直接当回调传给按钮的 addEventListener,点击时控制台爆红:Cannot read properties of undefined (reading 'state')。同样的事发生在 setTimeout(panel.refresh, 1000) 上。这方法明明是 panel 的,this 怎么会是 …- 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
-
一个在 forEach 回调里写 await 的批处理脚本,以为会一个个等着处理完,结果还没处理完就往下走、还吞掉了异常:一次 JavaScript 异步遍历的深度复盘
数据迁移脚本用 forEach 遍历、在回调里 await 逐条同步,处理完打印'全部同步完成'。结果那句几乎立刻就打印了(其实没同步完),而且某条失败抛的异常外层 try-catch 一个都没抓到、变成了 UnhandledPromiseRejection。根因是 Array.prototype.forEach 是同步遍历、完全忽略回调返回的 Promise、不会等待 awa…- 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
-
我做金额计算,0.1 加 0.2 居然不等于 0.3,累加几笔钱后总额还对不上、比较相等也失败,我对着 JavaScript 浮点数无法精确表示小数这个坑排查了大半天的复盘
一个让我对计算机里的小数到底是什么彻底搞明白的坑,简单到难以置信却坑得怀疑人生:在 JavaScript(其实几乎所有语言)里 0.1+0.2 不是 0.3 而是 0.30000000000000004。涉及金额的功能,直接用浮点算:0.1+0.2===0.3 是 false、累加 10 次 0.1 得 0.9999999999999999、付 0.3 元(0.1+0.2)却被判付的不够。深究 I…- 2
- 0
-
我用 forEach 配 async/await 批量处理数组,在 forEach 后面以为全都处理完了,结果它根本没等就往下走了,数据全乱套,我对着 forEach 不会等待异步回调这个坑排查了大半天的复盘
一个让我对 JavaScript 异步与数组遍历的结合彻底搞清楚的坑,诡异在我在每个元素上都老老实实写了 await 看起来应该会等,可整个 forEach 根本没等任何一个异步操作完成就执行到了后面。要对数组每个元素做异步操作(逐个存库)再汇总,自然用了 items.forEach(async (item) => { await saveToDb(item) }),然后 console.l…- 0
- 0
-
我把对象的一个方法作为回调传给了 setTimeout,运行时它里面的 this 竟然变成了 undefined,直接报错,我对着 JavaScript 的 this 取决于怎么调用而非在哪定义这个坑排查大半天的复盘
一个让无数从其他语言转来的人对 JavaScript 又恨又怕的经典坑——this。折磨在同一个方法在对象上直接调用一切正常,一旦传出去作回调 this 就神秘变了。有个对象 timer 封装了 seconds 和 tick 方法(tick 里用 this.seconds++)。直接 timer.tick() 正常,但 setTimeout(timer.tick, 1000) 一秒后报错 Cann…- 3
- 0
-
我对一个数字数组调了 sort() 排序,结果 10 竟然排在了 2 的前面,整个榜单顺序全乱,我对着 JavaScript 的 sort 默认按字符串字典序排序这个坑排查大半天的复盘
一个堪称 JavaScript 新手必踩、老手偶尔也栽的经典坑。做一个排行榜功能,要把一组用户积分从小到大排好序展示。积分是数字、数组在手,我想都没想就调了 scores.sort()。期望 [1,2,3,10,21,25,100],实际打印出来却是 [1,10,100,2,21,25,3]——10、100 排在了 2 前面,3 排到了最后,顺序毫无道理,既不升序也不降序像被随机打乱。换几组数字试…- 0
- 0
-
我复制了一个对象去改副本,结果原对象也跟着被改了、数据莫名其妙被污染,我对着 JavaScript 的浅拷贝和引用共享排查了大半天的复盘
写表单逻辑,有份原始数据,想在不动原数据的前提下复制一份在副本上改(做编辑预览),用了看起来很标准的展开运算符复制。结果诡异:明明只改了副本,原始数据竟然也跟着变了,页面上原始和修改后显示成一样的、数据被污染。盯着代码反复看,都已经 {...原对象} 复制一份了改副本怎么会影响原对象?排查大半天才理解 JS 两个核心概念——引用类型和浅拷贝:JS 对象/数组是引用类型,变量存的是指向对象的引用;{…- 0
- 0
-
我用 == 判断一个值是否为空,结果空字符串、数字 0、空数组全被判成了"相等",逻辑全乱了,我对着 JavaScript 的隐式类型转换排查了大半天的复盘
用 JS 写表单校验和默认值处理,用 == 做各种判断,代码看着很顺,上线后行为诡异到离谱:用户输入数字 0 被当成空、空数组 [] 被判成等于 false、字符串 "0" 和数字 0 一会儿相等一会儿不相等,整个校验乱成一锅粥。盯着那些 == 看了又看,每个单独看好像挺合理,组合起来就是不对。排查大半天才理解 JS 臭名昭著的特性——== 的隐式类型转换:0=="&…- 0
- 0
JavaScript
幸运之星正在降临...
点击领取今天的签到奖励!
恭喜!您今天获得了{{mission.data.mission.credit}}积分
我的优惠劵
-
¥优惠劵使用时效:无法使用使用时效:
之前
使用时效:永久有效优惠劵ID:×
没有优惠劵可用!
























