jstips 技巧 15:用 `~` 位运算把 `indexOf` 变成优雅的 contains 判断
教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载JavaScript 原生没有提供contains方法日常判断字符串是否包含某个子串或数组是否包含某个元素时最常见的写法是someText.indexOf(javascript) ! -1。本文基于 jstips 仓库 的 Tip 15原文讲解如何用位运算~将indexOf的返回值直接当作布尔值使用并对比 ES6/ES7 引入的includes()方法让你在字符串与数组的包含性判断上写出更简洁、可读的代码同时清楚每种写法的适用前提与兼容性边界。常规做法indexOf 显式比较String.prototype.indexOf()与Array.prototype.indexOf()都会在找不到时返回-1找到时返回首次出现的索引非负整数。因此最常见的 contains 判断是var someText javascript rules; if (someText.indexOf(javascript) ! -1) { // someText 包含 javascript } // 等价写法 if (someText.indexOf(javascript) 0) { // someText 包含 javascript }两种写法完全等价只是! -1语义上更贴近存在性判断而 0强调索引合法。它们都正确但略显啰嗦——你真正关心的只是一个布尔结果却不得不和一个魔法数字-1做比较。更简洁的写法利用位运算~Express 源码中大量使用了一个更简洁的技巧。以 examples/mvc/lib/boot.js 中的片段为例for (var key in obj) { // reserved exports if (~[name, prefix, engine, before].indexOf(key)) continue;这里用~按位取反bitwise NOT包裹indexOf的返回值直接在if条件里充当布尔值。同样lib/utils.js 用它判断 MIME 类型是否包含/exports.normalizeType function(type){ return ~type.indexOf(/) ? acceptParams(type) : { value: mime.lookup(type), params: {} }; };而在 examples/web-service/index.js 中则用!~表达不包含// key is invalid if (!~apiKeys.indexOf(key)) return next(error(401, invalid api key));为什么~能这样用位运算~对数字按二进制位取反运算过程基于 32 位二进制表示但返回的是标准 JavaScript 数值。关键规律是~(-1) 0其它非负整数 n 的~n均为负数例如~0 -1、~1 -2、~2 -3由于indexOf找不到时返回-1找到时返回 0的索引因此~indexOf(...)为0⇔ 索引为-1⇔不包含而0在if条件中为 falsy~indexOf(...)为非 0 ⇔ 索引 0⇔包含非 0 值在if条件中为 truthy。也就是说~把indexOf的返回值归一化成了可直接用于条件判断的真值省掉了与-1的比较。验证一下var someText text; !!~someText.indexOf(tex); // someText contains tex - true !~someText.indexOf(tex); // someText NOT contains tex - false ~someText.indexOf(asd); // someText doesnt contain asd - false ~someText.indexOf(ext); // someText contains ext - true配合双重取反!!可以把它严格规范为布尔值true/false配合!~则直接表达不包含。需要注意的边界~是一个通用位运算它的行为并不只服务于indexOf使用时务必留意两点可参见同仓库 Tip 18双波浪号截断 对位运算的深入剖析只对找不到返回 -1的 API 成立indexOf的返回值恰好是-1或 0这是该技巧能成立的前提。若某个 API 在失败时返回null、undefined或其他值~的结果会不可预测。32 位整数限制位运算会把操作数先转成 32 位有符号整数。对索引值而言通常无碍但若数值超出 32 位范围约 ±21.47 亿结果会失真。日常的字符串/数组索引场景基本不会触发但不要把它推广到任意大数的位运算上。更现代的替代方案includes()ES6 为字符串引入了String.prototype.includes()可以直接判断一个字符串是否包含另一个字符串something.includes(thing); // trueECMAScript 2016ES7又把includes()扩展到了数组用法与indexOf风格一致!!~[1, 2, 3].indexOf(1); // true [1, 2, 3].includes(1); // true相比之下includes()语义直白、可读性最好是团队协作与长期维护场景下的首选。仓库内其他 Tip 也大量使用了includes()处理剔除某些键之类的判断例如 Tip 70picking and rejecting object properties 中的Object.keys(obj).filter(k !keys.includes(k))可作为实际工程中的参考用法。兼容性前提注意includes()仅被 Chrome、Firefox、Safari 9 及以上版本和 Edge 支持IE11 及更低版本不支持它更适合在可控的运行环境中使用。若需要兼容旧环境退回到indexOf系列的写法即可。另外Array.prototype.includes()与indexOf在判断NaN上行为不同[NaN].indexOf(NaN)返回-1而[NaN].includes(NaN)返回true两者对0/-0的判定也有细微差别需要精确判断元素时要注意。小结写法示例特点indexOf! -1s.indexOf(x) ! -1语义清晰兼容所有环境位运算~~s.indexOf(x)/!~s.indexOf(x)最简洁老代码中常见但依赖 32 位位运算语义String/Array.includes()s.includes(x)/arr.includes(x)语义最佳ES6/ES7 特性需注意 IE11 不支持三种方式都能完成包含性判断。作为工程建议新代码优先使用includes()在必须兼容旧浏览器或需要强调存在索引的场景下使用indexOf ! -1而~技巧适合在受控环境、追求极简表达例如配合!~表示不包含并提前return/continue时使用同时牢记其位运算边界。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐WPScan 动态版本检测实战以 Grid Plus 插件 CHANGELOG.md 为例解析 ChangeLog 版本指纹机制WPScan 动态版本检测实战以 Grid Plus 插件 CHANGELOG.md 为例解析 ChangeLog 版本指纹机制 WPScan 作为面向 Wo教程终极bash条件判断简写指南与||运算符应用技巧终极bash条件判断简写指南与||运算符应用技巧 想要快速掌握bash脚本中的条件判断技巧吗作为Linux和Unix系统中最重要的shell编程语言b教程剑指 Offer 15 二进制中 1 的个数逐位判断与 n(n-1) 位运算解法详解Python/Java/C剑指 Offer 15 二进制中 1 的个数逐位判断与 n n 1 位运算解法详解Python/Java/C 本篇基于 LeetCode Book示例工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

eFuse+MCU实现工业级电源路径保护:从原理到实操

eFuse+MCU实现工业级电源路径保护:从原理到实操

做嵌入式和工业硬件设计这些年,电源路径保护一直是个“平时不起眼、出事就背锅”的环节。很多项目前期都在卷主控性能、赶协议栈、调通信接口,电源部分往往扔一个自恢复保险丝或者一个PMOS开关就完事,结果一到现场就出问题:电机启…

2026/10/8 6:39:31 阅读更多 →
电子保险丝eFuse与MCU协同:电源路径保护方案设计与实践

电子保险丝eFuse与MCU协同:电源路径保护方案设计与实践

做嵌入式硬件和底层软件的朋友,应该都体会过被电源问题支配的感觉。系统明明跑得挺好,现场一个插拔、电机启动,或者别的设备短路,直接把板子的总线电压拉垮,单片机复位,逻辑乱套,严重时 DC-DC 直…

2026/10/9 10:48:21 阅读更多 →
双十一 ABS+PC 行李箱品牌横评:别被销量排行榜忽悠,5 款热门机型真实对比

双十一 ABS+PC 行李箱品牌横评:别被销量排行榜忽悠,5 款热门机型真实对比

一、先别急着冲品牌:先定需求,再谈品牌品牌对比的前提,是先明确你的使用场景。同样标注 ABSPC,20 寸和 28 寸解决的根本不是同一个问题;同一个品牌,不同系列的配置、品控、质保也可能天差地别。1. 先定尺寸…

2026/10/8 6:38:29 阅读更多 →

最新新闻

SpringBoot+MyBatis-Plus多数据源实战:从配置到踩坑

SpringBoot+MyBatis-Plus多数据源实战:从配置到踩坑

如果你跟我一样在业务增长比较快的团队里做后端,大概率早晚会遇到同一个SpringBoot项目连两个甚至多个数据库的需求。我最早碰多数据源是在订单和报表分库的时候,主库扛写入,报表库跑复杂查询,两边数据要在一个服务里同时访问。当…

2026/10/9 12:45:12 阅读更多 →
大屏开发必备:89字节最短CSS性能优化实践

大屏开发必备:89字节最短CSS性能优化实践

1. 为什么“最短CSS”在大数据演示屏里不是炫技,而是刚需你有没有见过那种大屏项目:前端同事写完一版,部署到LED拼接屏上,CPU占用率直接飙到95%,动画卡成PPT,运维半夜被报警电话叫醒?我去年参与…

2026/10/9 12:45:12 阅读更多 →
iOS NSData 源码实战:二进制数据处理与避坑指南

iOS NSData 源码实战:二进制数据处理与避坑指南

简介:这份资源是面向iOS开发初学者与进阶者的NSData实战源码包,聚焦Objective-C中Foundation框架核心类NSData的数据处理能力。内容围绕二进制数据存储、文件读写、JSON序列化与归档、Base64编码、AES加密、网络请求体封装及图片数据转换等典型场景展开&…

2026/10/9 12:45:12 阅读更多 →
JSONP跨域请求原理详解与实战实现方案

JSONP跨域请求原理详解与实战实现方案

1. 跨域请求的痛点与 JSONP 的诞生逻辑前后端分离开发的日常里,跨域几乎是绕不开的一道坎。前端页面跑在http://localhost:8080,后端接口部署在http://api.example.com,浏览器控制台立刻甩出一行红字:Access-Control-Allow-Origin…

2026/10/9 12:45:12 阅读更多 →
HTTP为何能靠TCP“躺赢”?从协议栈分工到工业排障全解析

HTTP为何能靠TCP“躺赢”?从协议栈分工到工业排障全解析

把Wireshark打开,盯一条HTTP请求的完整生命周期走一遍,你大概率会得出跟我一样的结论:HTTP跑起来实在是太省心了。丢包重传、乱序重组、连接建立与释放、流量与拥塞控制,这些又脏又累的活,统统被TCP协议扛在了自己肩上…

2026/10/9 12:45:12 阅读更多 →
TX1串口调试实战:ttyTHS1与ttyTHS2区别、配置与避坑指南

TX1串口调试实战:ttyTHS1与ttyTHS2区别、配置与避坑指南

1. 从一块开发板的调试口说起:tx1串口到底特殊在哪很多人第一次接触tx1的串口,都是因为系统起不来、网络不通、或者想进控制台看看内核打印。这块板子的串口不像普通单片机那样随便找个UART就能用,它的调试串口和通用串口在设备树里是分开配置…

2026/10/9 12:44:11 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →