Negated in and instanceof operators S1
中文标题:取反的 in 和 instanceof 运算符
- 阶段: Stage 1
- 状态: 进行中
- ECMAScript 版本: —
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案引入了取反运算符 !in 和 !instanceof,以简化对 in 和 instanceof 检查的逻辑取反表达。它解决了在表达式中使用 ! 运算符时因错误加括号而产生的常见错误和可读性问题。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
取反的 in 和 instanceof 运算符
状态
阶段: 1
负责人: Pablo Gorostiaga Belio (@gorosgobe)
作者
Pablo Gorostiaga Belio (@gorosgobe)
提案
演示文稿
动机
JavaScript 的 in 和 instanceof 运算符大致具有以下行为:
为了取反这些表达式的结果,我们可以使用逻辑非(!)运算符将它们包裹起来:
以这种方式取反 in/instanceof 表达式存在一些问题:
易出错1
逻辑非运算符 ! 必须应用于整个表达式才能产生预期的结果。对子表达式(可以是任意长度表达式的一部分)的错误加括号和/或将 ! 运算符应用于错误的操作数可能导致难以调试的错误,例如:
对于 in:
对于 instanceof:
这种类型的错误相当常见。对于 in,此 Sourcegraph 查询 显示在 GitHub 上拥有数千星标的仓库中存在许多此类问题(我运行时有超过约 2100 个实例)。虽然存在一些误报(例如来自评论),但我在下面突出显示了一些值得注意的例子:
示例
同样,对于 instanceof,此 Sourcegraph 查询 显示也存在许多此错误的实例(我运行时约有 1.9 万次)。如前所述,拥有数千星标的仓库也受到影响。以下是一些示例:
示例
在彭博社内部,我们鼓励使用 eslint 和 TypeScript,它们各有针对这些情况的错误提示。然而,由于我们允许团队自行决定部分工具选择,错误仍然蔓延开来:在一大批内部项目中,我们发现大约八分之一的 in/instanceof 用法是取反的 in 和 instanceof 表达式。超过 1% 的取反 in 用法存在此错误。这也影响了取反的 instanceof,其中超过 6% 的用法存在此错误。我们的内部结果与外部 sourcegraph 查询的数据一致:取反的 instanceof 表达式中的错误发生率明显高于取反的 in 表达式。虽然我们现在正在内部修复此问题,但总体而言,这些结果表明,由于取反的 in 和 instanceof 表达式缺乏易用性,这是一个常见问题。
产生困惑
这些表达式的取反与具有取反版本的运算符(如 ===/!==)不一致。这会在开发人员中产生困惑,并导致诸如 JavaScript 中是否有用于检查对象属性的“not in”运算符? 和 Javascript !instanceof If 语句 等高赞高浏览问题。
可读性
为了取反 in/instanceof 表达式的结果,我们需要引入额外的分组运算符(用两个括号表示)。此外,not 位于表达式的开头,这与自然英语的读法不同。这两个因素共同导致代码可读性降低。
较差的开发体验
在条件语句中使用 in/instanceof 作为守卫是很常见的。反转这些条件以减少代码缩进(如这与代码复杂度相关所示)可以提高代码的可读性和质量。使用现有运算符时,反转条件中的表达式需要同时用括号包裹并且取反。
解决方案
!in,是 in 的取反版本,其中
等价于
!instanceof,是 instanceof 的取反版本,其中
等价于
- 更安全:不再需要引入额外的分组,取反直接应用于运算符本身,而不是应用于表达式中左侧操作数旁边。
- 提高可读性:不再需要额外的分组来取反表达式的结果。这与
!==等其他运算符保持一致。读起来更自然,更直观。 - 更好的开发体验:同样,在重构代码时更容易更改 - 只需添加一个
!即可取反表达式。
在其他语言中:
Python:
Kotlin:
C#:
Elixir:
相关提案
模式匹配
模式匹配提案提出了一种新的关系表达式,如 a in b 或 a instanceof b,使用新的运算符 is:https://github.com/tc39/proposal-pattern-matching#is-expression
与 in 和 instanceof 类似,我们可以扩展该提案以包含取反的 is 运算符,例如 !is。
Footnotes
-
关于 TypeScript 的说明:如果使用 TypeScript,易出错性没有那么令人担忧,因为 TypeScript 会检查传递给
in和instanceof运算符的类型是否正确。但是,类型错误或缺少类型仍然可能导致此问题。如果你不使用 TypeScript,或者代码的特定部分是无类型的或显式使用any,也可能发生这种情况。 ↩