news 2026/7/28 12:55:52

新的数组方法如find、includes:实用技巧实战案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
新的数组方法如find、includes:实用技巧实战案例

findincludes:让数组操作更聪明、更优雅

你有没有过这样的经历?在处理用户权限时,写了一堆for循环去遍历数组;判断某个值是否存在时,还得查文档确认indexOf返回-1才表示“没找到”;甚至因为一个NaN的比较问题,调试了半小时才发现是方法选错了。

其实,这些“老派”的写法早已被现代 JavaScript 更优雅的方案取代。从 ES6 开始,findincludes这两个方法就像两把精准的小刀,专门解决我们日常开发中最常见的两类问题:

  • 我要找符合条件的第一个元素→ 用find
  • 这个值到底在不在数组里?→ 用includes

它们不仅让代码变短,更重要的是——读起来像人话


find:别再手动 break 了,交给它来找第一个匹配项

它到底做了什么?

假设你有一组用户数据:

const users = [ { id: 1, name: 'Alice', role: 'admin' }, { id: 2, name: 'Bob', role: 'user' }, { id: 3, name: 'Charlie', role: 'user' } ];

你想找出那个管理员。传统做法可能是这样:

let adminUser = undefined; for (let i = 0; i < users.length; i++) { if (users[i].role === 'admin') { adminUser = users[i]; break; // 别忘了这句!否则继续浪费性能 } }

而用find,一句话搞定:

const adminUser = users.find(user => user.role === 'admin'); // { id: 1, name: 'Alice', role: 'admin' }

是不是清爽多了?

关键特性一览

特性说明
✅ 只返回第一个匹配项找到就停,不浪费资源
🔄 不修改原数组符合函数式编程原则
⚡ 支持短路求值性能优于filter()[0]
💬 语义清晰“find” 就是“找一个”,意图明确

🔍 提示:如果你需要的是索引而不是元素本身,记得使用findIndex(),它的行为完全一致,只是返回下标。

实战场景:根据 ID 查用户详情

这是前端最常见的需求之一——点击某个用户的卡片,弹出其详细信息。

function getUserById(userId) { return users.find(u => u.id === userId); } // 使用 const user = getUserById(2); if (user) { showModal(user.name); } else { alert('用户不存在'); }

你会发现,整个逻辑变得非常线性:查找 → 判断 → 使用,没有中间变量,也没有复杂的控制流。

安全访问技巧:可选链(Optional Chaining)

为了防止undefined报错,可以结合?.操作符:

const userName = users.find(u => u.id === 999)?.name || '未知用户';

这一行代码已经足够健壮,既避免了空指针异常,又保持了简洁性。


includes:告别indexOf !== -1,真该退休了

为什么说indexOf不够好?

我们曾经都这么写过:

if (roles.indexOf('admin') !== -1) { enableAdminPanel(); }

这段代码能运行,但有几个痛点:

  1. 可读性差:“不等于 -1” 是反直觉的表达
  2. 容易出错:新人可能误写成=== -1
  3. 无法识别 NaN[NaN].indexOf(NaN)居然返回-1

includes直接解决了这些问题:

if (roles.includes('admin')) { enableAdminPanel(); // 看起来就像自然语言 }

而且对NaN完全友好:

[1, 2, NaN, 4].includes(NaN); // true ✅

这才是现代 JS 应有的样子。

方法签名也很贴心

arr.includes(searchElement, fromIndex?)

第二个参数允许你指定起始位置,比如:

const arr = ['a', 'b', 'c', 'b']; arr.includes('b'); // true(从头开始) arr.includes('b', 2); // true(从第三个元素开始找) arr.includes('b', 3); // true(还能找到最后一个) arr.includes('b', 4); // false(超出范围)

还支持负数索引:

arr.includes('b', -2); // true(倒数第二个位置开始)

这种灵活性让你可以在子区间内做存在性判断,非常适合状态机或流程控制类逻辑。


联手出击:真实项目中的经典配合

让我们看一个典型的业务场景:用户登录后初始化权限。

function initUserPermissions(user) { const permissionRules = [ { role: 'admin', actions: ['create', 'edit', 'delete', 'view'] }, { role: 'editor', actions: ['edit', 'view'] }, { role: 'viewer', actions: ['view'] } ]; // 第一步:通过角色找到对应的权限配置 const rule = permissionRules.find(r => r.role === user.role); if (!rule) { throw new Error(`无效角色: ${user.role}`); } // 第二步:检查是否拥有编辑权限 if (rule.actions.includes('edit')) { renderEditButton(); } // 第三步:保存可用操作列表 user.allowedActions = rule.actions; }

看看这里发生了什么:

  • find负责“定位”
  • includes负责“判断”
  • 整个过程没有任何临时变量或嵌套条件
  • 逻辑清晰得像一篇小作文

这就是声明式编程的魅力:你告诉程序“要做什么”,而不是“怎么做”。


常见误区与避坑指南

❌ 误用find去做存在性判断

错误示范:

if (users.find(u => u.name === 'Alice')) { ... }

虽然也能工作,但语义不清。你应该用someincludes来表达“是否存在”:

if (users.some(u => u.name === 'Alice')) { ... } // ✔ 推荐

✅ 规则总结:
- 要“取值” →find
- 要“判断存在” →some/includes
- 要“全部满足” →every

❌ 期望includes能比较对象内容

[{ a: 1 }].includes({ a: 1 }); // false ❌

因为includes使用的是严格相等(===),只比较引用地址,不深挖内容。

正确做法是使用some配合自定义逻辑:

const hasObj = array.some(item => item.a === 1 && item.b === 2);

或者引入 Lodash 的isEqual做深度比较。

⚠️ 注意undefined的陷阱

find找不到时返回undefined,直接访问属性会报错:

users.find(u => u.id === 999).name; // TypeError!

务必先判断或使用可选链:

users.find(u => u.id === 999)?.name; // 安全

性能与工程化考量

小数组没问题,大集合怎么办?

对于小于 1000 项的数据,findincludes的性能完全够用。但如果频繁查询上万条记录,建议提前建立索引结构:

// 构建 ID 映射表(O(1) 查询) const userMap = new Map(users.map(u => [u.id, u])); // 后续查询极快 const user = userMap.get(1);

但这并不意味着你要放弃find。相反,在大多数 CRUD 场景中,find依然是最合适的选择——简单、安全、易维护

兼容性处理:别让 IE 拖后腿

IE 全系列不支持findincludes。但在现代工程体系下,这不是问题:

  • 使用 Babel +@babel/preset-env
  • 配置targets自动注入 polyfill
  • 或手动引入 core-js:
npm install core-js --save

然后在入口文件加入:

import 'core-js/stable/array/find'; import 'core-js/stable/array/includes';

构建工具会帮你搞定一切。


写在最后:代码质量,从每一个小选择开始

findincludes看似只是两个小方法,但它们背后代表着一种思维方式的转变:

从“如何实现”转向“想要什么”

当你写下.find()的那一刻,你就不再关心循环怎么写、要不要 break、索引会不会越界。你只需要表达你的目的,剩下的交给语言 runtime。

这正是现代 JavaScript 的进化方向:更高层次的抽象,更强的表达力,更低的认知负担

未来还会出现更多类似的方法,比如正在提案中的.findLast().groupBy().tap()……作为开发者,我们要做的不是死记硬背 API,而是理解它们的设计哲学——让代码更接近人的思维,而非机器的执行路径

所以,下次你在写for循环之前,不妨问自己一句:

“有没有一个方法,名字就叫‘我想找第一个满足条件的’?”

答案往往是:有,它叫find

如果你在实际项目中遇到类似的挑战,欢迎留言讨论,我们一起打磨更优雅的代码。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/22 3:21:03

Qwen3-0.6B教育场景落地:智能批改系统搭建教程

Qwen3-0.6B教育场景落地&#xff1a;智能批改系统搭建教程 1. 引言 随着大语言模型在自然语言理解与生成能力上的持续突破&#xff0c;其在教育领域的应用正逐步从理论探索走向实际落地。尤其是在作业批改、作文评分、错题分析等高频教学场景中&#xff0c;自动化、智能化的辅…

作者头像 李华
网站建设 2026/7/24 20:26:17

Sambert模型版本管理:多版本共存与切换策略

Sambert模型版本管理&#xff1a;多版本共存与切换策略 1. 引言 1.1 场景背景 在语音合成&#xff08;TTS&#xff09;系统的实际开发与部署过程中&#xff0c;模型的迭代更新是常态。Sambert-HiFiGAN 作为阿里达摩院推出的高质量中文语音合成方案&#xff0c;因其自然流畅的…

作者头像 李华
网站建设 2026/7/24 22:28:17

5分钟部署Qwen3-Embedding-4B,零基础搭建企业级语义检索系统

5分钟部署Qwen3-Embeding-4B&#xff0c;零基础搭建企业级语义检索系统 1. 引言&#xff1a;为什么企业需要私有化语义检索能力&#xff1f; 在非结构化数据年均增长超过40%的今天&#xff0c;传统关键词匹配已无法满足企业对精准信息获取的需求。尤其在金融、医疗、法律等高…

作者头像 李华
网站建设 2026/7/26 7:34:20

system prompt适应性测试:Qwen2.5-7B角色扮演体验

system prompt适应性测试&#xff1a;Qwen2.5-7B角色扮演体验 1. 引言 在大语言模型的应用落地过程中&#xff0c;如何让模型精准地“认知自我”并执行特定角色任务&#xff0c;是提升用户体验的关键环节。随着 Qwen2.5 系列模型的发布&#xff0c;其对 system prompt 的更强…

作者头像 李华
网站建设 2026/7/26 17:25:02

快速集成:将AWPortrait-Z模型嵌入现有系统的完整指南

快速集成&#xff1a;将AWPortrait-Z模型嵌入现有系统的完整指南 你是否正在为产品中的人像美化功能发愁&#xff1f;传统美颜算法效果生硬&#xff0c;AI方案又部署复杂、调用困难&#xff1f;别担心&#xff0c;今天我要分享的这个方法&#xff0c;能让你在最短时间内把高质…

作者头像 李华
网站建设 2026/7/26 5:37:52

LangFlow金融风控应用:反欺诈规则引擎可视化设计

LangFlow金融风控应用&#xff1a;反欺诈规则引擎可视化设计 1. 引言 在金融行业&#xff0c;欺诈行为的识别与防范是保障业务安全的核心环节。传统的反欺诈系统依赖于复杂的规则引擎和大量人工干预&#xff0c;开发周期长、维护成本高&#xff0c;且难以快速响应新型欺诈模式…

作者头像 李华