Skip to content

📜 卷③ JavaScript 与 TypeScript

20 条。适用场景:语言和运行时层面现在有什么新工具,以及哪些老做法可以退休了

「要点」「我的补充」为本人撰写,非原文摘录。

← 返回前端资料库总览


一、语言新能力:可以删掉依赖了

41. JavaScript Temporal is coming

来源:MDN Blog · developer.mozilla.org 读它解决什么Date 的设计缺陷你忍了很多年,Temporal 是正式的替代品。

要点

  • Date 的核心问题:月份从 0 开始、可变对象、时区处理弱、解析行为依赖实现
  • Temporal 用一组明确区分的类型解决:PlainDate(无时区日期)、PlainDateTimeZonedDateTime(带时区)、Instant(时间点)、Duration
  • 全部不可变,运算返回新对象,这消除了一大类隐蔽 bug

我的补充:类型区分是它最大的价值——"生日"应该是 PlainDate(不带时区,不然跨时区显示会差一天),"会议时间"应该是 ZonedDateTimeDate 存生日导致的跨时区差一天是最经典的日期 bug。迁移策略:新代码直接用 Temporal(需要 polyfill 时用 temporal-polyfill),旧代码不必急着改。用上它之后 date-fnsdayjs 这类库多数场景可以删掉。

阅读原文 →


42. New JavaScript Set methods

来源:MDN Blog · developer.mozilla.org 读它解决什么:集合的交集、并集、差集终于原生支持,不用再手写。

要点

  • 新增 unionintersectiondifferencesymmetricDifference,以及判定方法 isSubsetOfisSupersetOfisDisjointFrom
  • 此前这些操作要靠 [...a].filter(x => b.has(x)) 之类的写法,可读性和性能都不理想
  • 参数可以是任何"类 Set"对象(有 sizehaskeys

我的补充:可读性提升很直接:a.intersection(b) 对比 new Set([...a].filter(x => b.has(x)))。实际用得最多的是权限判断——userPerms.isSupersetOf(requiredPerms) 比循环清楚得多。注意这些方法返回新 Set,不修改原对象。老环境的话 core-js 有 polyfill,但先想想是不是可以直接用数组解决,小集合上差别不大。

阅读原文 →


43. Locale-sensitive text segmentation with Intl.Segmenter

来源:MDN Blog · developer.mozilla.org 读它解决什么:按"字符"截断字符串结果乱了——emoji 变方块、中文和英文的分词规则不同。

要点

  • JS 字符串是 UTF-16 码元序列,.length[i] 都不是"用户看到的字符",emoji 和组合字符会被切坏
  • Intl.Segmenter 按语言规则切分:grapheme(用户感知字符)、word(词)、sentence(句)
  • 中日韩没有空格分词,word 粒度必须靠这类 API

我的补充截断字符串做摘要时必须用 grapheme 粒度,否则 emoji(尤其带肤色修饰符、ZWJ 组合的家庭 emoji)会被切成乱码方块。'👨‍👩‍👧'.length 是 8,用 slice(0, 4) 就毁了。中文摘要计算"字数"也该用它,而不是 .length。这个博客的文章摘要如果做自动截断,就该用这个而不是 substring

阅读原文 →


44. Creating color palettes with the CSS color-mix() function

来源:MDN Blog · developer.mozilla.org 读它解决什么:主题色需要程序化派生,想知道 CSS 侧和 JS 侧该怎么配合。

要点

  • color-mix() 在指定色彩空间里按比例混合两色,可以从一个基色派生整套明暗变体
  • 混合所用的色彩空间影响结果:oklch 的插值比 srgb 更符合视觉预期
  • 与自定义属性配合,可以做到"改一个变量整站换色"

我的补充:动态主题(用户自选主题色)的现代实现就是它——JS 只需写一个 --brand 变量,其余色阶全交给 CSS 派生,比在 JS 里算颜色再注入十几个变量干净得多。要点是混合空间选 oklchcolor-mix(in oklch, var(--brand), white 20%) 得到的浅色比 in srgb 自然得多,后者容易发灰。

阅读原文 →


45. Image formats: Codecs and compression tools

来源:MDN Blog · developer.mozilla.org 读它解决什么:该用 WebP 还是 AVIF,以及压缩参数怎么定。

要点

  • 有损与无损、逐行与渐进、编码耗时与解码耗时是几个独立的维度,不能只看文件大小
  • AVIF 压缩率通常优于 WebP,但编码慢得多,且解码在低端设备上有成本
  • 工具链选择(sharpsquooshcwebp)影响可自动化程度

我的补充:实用结论:照片类用 AVIF 或 WebP,图标和纯色图形用 SVG,截图类 WebP 无损常常小于 PNG。用 <picture> 加多个 <source> 让浏览器挑,兼容性问题自然解决。这个博客的壁纸全部是 .webp,25 张图对首屏加载影响明显小于 JPEG。批量转换用 sharp 脚本比手工快得多,注意保留原图以便日后重新编码。

阅读原文 →


46. Image formats: Pixel data from encoders to decoders

来源:MDN Blog · developer.mozilla.org 读它解决什么:理解图片编解码的原理,从而知道压缩参数为什么这样影响质量。

要点

  • 有损压缩的核心手段是丢弃人眼不敏感的信息:色度子采样、频域变换后量化
  • 因此图片内容决定最优参数:平滑渐变和锐利文字的最佳策略相反
  • 反复编码会累积损失(世代损失)

我的补充:两条可执行的推论。一是别对已经有损压缩过的图再压一次,每次都掉质量——保留无损原图作为唯一真源,所有派生版本从它生成。二是含文字的截图用有损格式会让字发虚(色度子采样的直接后果),这类图要么用无损 WebP/PNG,要么把质量拉到很高。

阅读原文 →


47. Image formats: Color models for humans and devices

来源:MDN Blog · developer.mozilla.org 读它解决什么:图片在不同屏幕上颜色不一致,或者 CSS 颜色和图片颜色对不上。

要点

  • 色彩模型(RGB、HSL、Lab、OKLab)与色彩空间(sRGB、Display P3)是不同层面的概念
  • 广色域屏幕上,未标注色彩空间的图片会被按 sRGB 解释,可能偏色
  • CSS 侧现在能表达 P3 色域的颜色,与图片的色彩管理需要对齐

我的补充:实际会遇到的问题:设计稿在 P3 屏幕上做的,导出成 sRGB 图片后颜色变灰。解决办法是导出时嵌入色彩配置文件,并在 CSS 里用 color(display-p3 ...) 表达对应颜色。多数博客场景不必深究——统一用 sRGB 就好,一致性比鲜艳更重要。

阅读原文 →


二、TypeScript:大版本的实际影响

48. Announcing TypeScript 7.0

来源:TypeScript DevBlog · devblogs.microsoft.com 读它解决什么:判断升到 7.0 要付出什么、得到什么。

要点

  • 大版本通常同时带来新语法能力与破坏性的类型检查收紧,后者是升级成本的主要来源
  • 升级前应通读 breaking changes,尤其涉及库类型声明的部分
  • 编译器性能改进对大型项目的开发体验影响很实际

我的补充:TypeScript 升级的标准流程:先在 CI 里加一个允许失败的 tsc --noEmit 任务跑新版本,看错误量级再决定节奏。错误集中在第三方 @types 包时,往往等上游更新比自己改快。另外别忘了 skipLibCheck: true 能挡掉大量第三方声明冲突,虽然不够严格但在迁移期很实用。

阅读原文 →


49. Announcing TypeScript 7.0 RC

来源:TypeScript DevBlog · devblogs.microsoft.com 读它解决什么:正式版之前想提前验证兼容性。

要点

  • RC 阶段 API 与行为已基本冻结,是做兼容性验证的合适时机
  • 此时反馈的问题还有机会在正式版修掉
  • 用 RC 跑一遍自己的项目,成本低于正式版发布后被动应对

我的补充:建议做法:pnpm add -D typescript@rc 在一个分支上跑 tsc --noEmit,把错误分类。只需要跑类型检查,不需要真的用它构建,风险极低。开源项目更应该做这件事——你的使用者会比你更早遇到问题。

阅读原文 →


50. Announcing TypeScript 7.0 Beta

来源:TypeScript DevBlog · devblogs.microsoft.com 读它解决什么:最早期了解下个大版本的方向。

要点

  • Beta 阶段公布主要特性方向,细节可能仍变
  • 适合了解趋势,不适合据此改代码
  • 关注点应放在"哪些现有写法会被判为错误"

我的补充:Beta 阶段最值得看的是弃用与收紧列表,因为那决定你的迁移工作量。新语法糖可以等正式版再学。一个长期有效的做法是:tsconfig.json 里尽量开严格模式(strict: true),严格模式下写的代码在版本升级时基本不会因为检查收紧而报错——问题总是出在宽松配置的项目上。

阅读原文 →


51. Announcing TypeScript 6.0

来源:TypeScript DevBlog · devblogs.microsoft.com 读它解决什么:了解 6.0 这一代引入的能力,很多项目仍在这个版本上。

要点

  • 版本公告是了解"某个语法从哪个版本开始可用"的权威来源
  • 对库作者尤其重要:package.json 里的 typesVersions 与最低支持版本要对应
  • 类型系统能力的增强(推断、模板字面量类型)通常无破坏性

我的补充:查"这个特性要求哪个 TS 版本"最快的方式就是翻版本公告。库作者请在 README 明确写出最低 TypeScript 版本——用了新语法但没声明,使用者会遇到莫名的类型报错。另外 tsconfigtarget 和 TS 版本是两件事,别混。

阅读原文 →


52. Trustworthy JavaScript for the Open Web

来源:Mozilla Hacks · hacks.mozilla.org 读它解决什么:用户凭什么相信网页里跑的 JS 没被篡改。

要点

  • 网页应用的代码每次访问都从服务器取,无法像原生应用那样一次性审计
  • 这对端到端加密类应用是根本问题:服务器可以随时下发一个偷密钥的版本
  • 解决方向涉及代码完整性验证与可复现构建

我的补充:这解释了为什么安全审计人员对"网页版端到端加密"持保留态度。对普通项目的可执行部分是子资源完整性(SRI):引用第三方 CDN 脚本时加 integrity="sha384-..."crossorigin,CDN 被投毒时浏览器会拒绝执行。这是很便宜的防护,但用的人不多。更彻底的做法是把第三方脚本自托管。

阅读原文 →


53. Securing APIs: Express rate limit and slow down

来源:MDN Blog · developer.mozilla.org 读它解决什么:接口被刷(暴力破解、爬取、滥用),需要限流。

要点

  • 限流(rate limit)直接拒绝超额请求,减速(slow down)逐步增加延迟,两者可组合
  • 关键设计是限流的键:按 IP 会误伤 NAT 后的用户,按用户需要已认证
  • 反向代理后面必须正确读取真实 IP,否则所有请求看起来来自同一个地址

我的补充trust proxy 配错是最常见的失效原因——Express 默认不信任代理头,在 Nginx/Cloudflare 后面拿到的 req.ip 是代理的 IP,于是全站共用一个限流配额,一个人就能把所有人锁死。Cloudflare 后面应读 CF-Connecting-IP。登录接口的限流应该按"IP + 账号"双维度,只按账号会被用来锁死别人的账号(这本身是一种攻击)。

阅读原文 →


三、引擎与运行时

54. How we made JSON.stringify more than twice as fast

来源:V8 Blog · v8.dev 读它解决什么:了解引擎层面的优化思路,顺便知道 JSON.stringify 的代价在哪。

要点

  • JSON.stringify 在服务端与前端都是热路径(日志、API 响应、状态序列化)
  • 优化通常来自减少中间字符串分配与针对常见形状(shape)走快路径
  • 这类改进无需改代码即可获得,但前提是升级引擎版本

我的补充:实用推论:序列化大对象是同步阻塞操作,主线程上 stringify 几十 MB 的数据会明显卡顿,Node 里会阻塞事件循环。真有大数据要序列化,考虑流式(JSONStream)或放进 Worker。另外别在渲染循环里 stringify 对象做比较(常见的"深比较"偷懒写法),代价比想象中高。

阅读原文 →


55. Giving V8 a Heads-Up: Faster JavaScript Startup with Explicit Compile Hints

来源:V8 Blog · v8.dev 读它解决什么:首屏 JS 解析编译耗时长,想让引擎优先编译关键函数。

要点

  • 引擎默认惰性编译(只在函数首次调用时编译),这减少启动开销但让首次调用有延迟
  • 显式编译提示允许标记"这些函数马上会用到,请提前编译"
  • 收益在大型应用的启动阶段最明显

我的补充:这类优化的前提是你的瓶颈真的在脚本编译——先用 DevTools Performance 面板看 Script Evaluation 的耗时占比,别凭猜测优化。多数站点的首屏瓶颈其实是网络和渲染,不是编译。真要减少编译开销,代码分割和少发 JS 的收益远大于编译提示

阅读原文 →


56. Land ahoy: leaving the Sea of Nodes

来源:V8 Blog · v8.dev 读它解决什么:了解 JIT 编译器内部表示的演进,理解性能为什么会变。

要点

  • 编译器中间表示(IR)的选择影响优化能力与编译速度,两者常有冲突
  • 换 IR 这类底层重构对开发者是透明的,但会改变性能特征
  • 这解释了为什么同一段代码在不同引擎版本上性能会有差异

我的补充:对日常开发的启示是别做基于特定引擎版本的微优化——那些"这样写比那样写快"的经验,往往在引擎更新后失效甚至反转。该做的是算法层面和架构层面的优化,那些是稳定的。真要做性能对比就在目标环境实测,别信几年前的 benchmark 文章。

阅读原文 →


57. Speculative Optimizations for WebAssembly using Deopts and Inlining

来源:V8 Blog · v8.dev 读它解决什么:了解 Wasm 的性能特征与优化机制。

要点

  • Wasm 传统上是提前编译、性能可预测,引入推测优化后能获得类似 JS JIT 的动态收益
  • 推测优化需要"去优化"(deopt)机制兜底:假设不成立时回退
  • 内联跨模块调用能消除边界开销

我的补充:这打破了"Wasm 性能恒定"的旧认知——现在它也有预热期了。对选型的影响:如果你选 Wasm 是为了"性能可预测"(比如实时音频处理),要重新验证。多数场景这是好事,因为峰值性能更高。实测仍是唯一可靠依据。

阅读原文 →


58. Evolving the Node.js Release Schedule

来源:Node.js 官方博客 · nodejs.org 读它解决什么:搞清 Node 的版本节奏,决定生产该用哪个版本。

要点

  • Node 有 Current 与 LTS 两条线:偶数版本会进入 LTS(长期支持),奇数版本不会
  • LTS 有 Active 与 Maintenance 两阶段,后者只修安全问题
  • 发布节奏调整会影响升级规划

我的补充:铁律是生产环境只用偶数号 LTS。查支持周期看 nodejs.org/en/about/previous-releases。CI 里建议同时跑当前 LTS 和下一个 LTS,能提前发现兼容问题。另外注意 package.jsonengines 字段要写实际测过的范围,写 >=18 但从没在 18 上跑过是在骗使用者。

阅读原文 →


59. Node.js 24.19.0 (LTS)

来源:Node.js 官方博客 · nodejs.org 读它解决什么:查看具体某个 LTS 版本的变更内容。

要点

  • 版本发布说明是判断"该不该升这个小版本"的一手依据,尤其含安全修复时
  • 语义化版本在 Node 这里执行得比较严格:LTS 的小版本升级通常安全
  • 关注 SEMVER-MINOR 标记的新增能力

我的补充:这正好是我本机在用的版本(node -v 显示 v24.19.0)。小版本更新应该跟得比较勤,尤其带安全修复的——Node 的安全公告通常同时放出多个受影响分支的修复版。用 nvmfnm 管多版本,别用系统包管理器装 Node,那通常版本很旧且升级麻烦。

阅读原文 →


60. Node.js Security Releases (July 2026)

来源:Node.js 官方博客 · nodejs.org 读它解决什么:确认自己的 Node 版本是否受某次安全公告影响。

要点

  • 安全发布公告列出受影响版本范围、漏洞影响与修复版本号
  • 需要判断的是你的使用方式是否触发该漏洞,而不只是版本号匹配
  • 多个 LTS 分支通常同时放出修复版

我的补充:订阅 Node 的安全公告(RSS 或邮件列表)比等扫描器报警及时。判断优先级看攻击面:如果漏洞需要处理不可信输入才能触发,而你的服务只跑内部任务,紧急程度就低。但基础镜像该定期重建——很多人的容器里跑着一年前的 Node。CI 里加 npm auditpnpm audit 能兜住依赖侧的问题。

阅读原文 →


本卷小结

三条:

  1. 截断字符串用 Intl.Segmenter 的 grapheme 粒度'👨‍👩‍👧'.length 是 8,用 slice 会切出乱码方块。
  2. Express 在代理后面必须配 trust proxy。不配则全站共用一个限流配额,一个人能锁死所有人。
  3. 生产只用偶数号 Node LTS,并且别用系统包管理器装 Node。

← 上一卷:浏览器平台能力 · 返回总览 · 下一卷:性能与可访问性 →