我不再在 JavaScript 里把所有东西链在一起

Hacker News Top 新闻

摘要

开发者 Matt Smith 解释,为了调试更轻松、性能更好,他现在在 JavaScript 中更偏爱一步步写代码,而不是冗长的方法链。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/04/22 13:13

# 为什么我不再在 JavaScript 里把所有东西串成链了 - Matt Smith 来源:https://allthingssmitty.com/2026/04/20/why-i-dont-chain-everything-in-javascript-anymore/ 我以前经常这么写 JavaScript: ```js const result = users .filter(user => user.active) .map(user => user.name) .sort() .slice(0, 5); ``` 这段代码本身没错,我以前一直这么写。但正是这种写法,一开始看着挺舒服,后来越来越难维护。 ## 链式调用很香……直到它不香 问题不在 `map()` 或 `filter()`,而在于你把它们叠罗汉。你写的不再是“步骤”,而是“管道”。 管道看着整洁,可你仍得在脑子里一步步走:filter → map → sort → slice。 偶尔来一回还行,满文件都是就容易让人崩溃。 对比一下: ```js const activeUsers = users.filter(user => user.active); const names = activeUsers.map(user => user.name); names.sort(); return names.slice(0, 5); ``` 行数多了,但每一步都摆在那儿,不用解码。 ## 同一个需求,三种写法 **链式:** ```js users.filter(u => u.active).map(u => u.name)[0] ``` 看着利落,我以前常用。可它把整张表都过一遍,其实我只想要一条数据。 **分步:** ```js const user = users.find(u => u.active); const name = user?.name; ``` 我通常选这种。早停早省力,哪不对劲也能逐点排查。 **完全掌控:** ```js for (const u of users) { if (u.active) return u.name; } ``` 最直白,有时候也是最容易看懂的写法。 ## 调试时最闹心 一旦要调试,链式的问题立刻放大。 想瞄一眼过滤后的结果?你得这么干: ```js const result = users .filter(user => { console.log(user); return user.active; }) .map(user => user.name); ``` 逻辑和调试代码混成一团,最后只能把链拆散。 ## 你可能白干了活 链式天然倾向于“全量处理”,哪怕你并不需要。 ```js const firstActiveUser = users .filter(user => user.active) .map(user => user.name)[0]; ``` 它把整张表过滤、映射,再取第一项。 其实你只想: ```js const user = users.find(user => user.active); const name = user?.name; ``` 或者: ```js for (const user of users) { if (user.active) { return user.name; } } ``` ## 代价在哪 这不只是可读性。数组一大或路径一热,多余的开销就肉眼可见。长链在线上调试也出奇地痛苦。 我以前写过不少“巨型链”,回头看……挺惭愧的。 ## 流畅 ≠ 清晰 链式受欢迎,是因为初读顺口: ```js data .transform() .normalize() .validate() .save(); ``` 可读完后你开始猜:每一步返回啥?断点往哪打?能不能复用? 拆成步骤,这些疑问立刻有答案。 ### 异步链也一个德行 Promise 链看着优雅: ```js const data = await fetchUsers() .then(res => res.json()) .then(users => users.filter(u => u.active)) .then(users => users.map(u => u.name)); ` 可你把异步控制(取数据、解析)和数据变换全混在一条链里。 拆开更易读: ```js const res = await fetchUsers(); const users = await res.json(); const activeNames = users.filter(u => u.active).map(u => u.name); ``` ## 我的土味经验法则 链长|建议|示例 ---|---|--- 1 步|随便写|`users.map(u => u.name)` 2 步|通常 OK|`users.filter(u => u.active).map(u => u.name)` 3–4 步|停一停,考虑拆|`users.filter(...).map(...).sort(...).slice(...)` 5+ 步|必须拆|复杂变换或异步链 ## 不是让你别链 短链我照写。一到三四步,我就踩刹车。 ### 我现在怎么想 写代码时链式快;读代码时步骤爽。两者不是一回事。 ### 我通常怎么拆 步骤|怎么做|示例 ---|---|--- 1|给中间结果起名|`const activeUsers = users.filter(u => u.active)` 2|逻辑拆分|`const names = activeUsers.map(u => u.name)` 3|只链清楚的部分|`names.sort()` 这招替我省了不少头疼。 JavaScript 工具箱很大,但不必一次全倒出来。 - JavaScript (https://allthingssmitty.com/tags/javascript)

相似文章

不久我们就能终于将 JavaScript 放逐至 ShadowRealm

Lobsters Hottest

本文探讨了 TC39 提出的 ShadowRealm 提案,该提案旨在允许在不使用 iframe 或 Web Workers 的情况下,在隔离环境(Realm)中执行 JavaScript,从而改善代码沙盒机制并提升性能。

就他妈用 React

Lobsters Hottest

这篇主观性很强的文章激进地主张在复杂 Web 应用中使用现代 JavaScript 框架(如 React)而非纯 HTML,认为复杂性需要合适的工具。

我决定回归手写代码

Hacker News Top

作者在重构一个 Kubernetes 仪表盘工具时反思道,虽然借助 AI 进行“氛围编程”(vibe-coding)能加速功能开发,但在缺乏人工监督的情况下,往往会导致架构臃肿和技术债务。

不再那么锁定了

Simon Willison's Blog

一篇博文讨论了编程语言的锁定效应如何因编码代理的兴起而减弱,以一家公司将原生iPhone和Android应用重写为React Native为例。