研究生做家教什么网站北京门户网站制作

张小明 2026/1/11 17:07:53
研究生做家教什么网站,北京门户网站制作,wordpress 链接 中文乱码,论坛类网站可以做移动端吗从手写实现到工程实战#xff1a;深入理解 ES6 中的 Set 与 Map 你有没有遇到过这样的场景#xff1f; 想给一个数组去重#xff0c;写了好几行 filter indexOf #xff0c;结果发现对象还去不掉#xff1b; 想用某个 DOM 节点当“键”来存一些临时数据#xff0c…从手写实现到工程实战深入理解 ES6 中的 Set 与 Map你有没有遇到过这样的场景想给一个数组去重写了好几行filterindexOf结果发现对象还去不掉想用某个 DOM 节点当“键”来存一些临时数据却发现 JavaScript 对象的键只能是字符串在做函数缓存时为了处理多个参数绞尽脑汁拼接 key最后还得担心命名冲突……这些问题在 ES6 出现之前几乎是每个前端开发者都踩过的坑。而今天我们要聊的主角 ——Set和Map正是为了解决这些痛点而生。它们不是花架子而是真正改变了我们组织和操作数据的方式。更重要的是理解它们的工作原理不仅能让你写出更高效的代码还能在面试中从容应对“手写一个 Set”这类高频题。为什么我们需要 Set数组去重真的那么简单吗我们先来看一个看似简单的问题如何对数组去重const arr [1, 2, 3, 2, 1]; // 方法一使用 filter indexOf const unique1 arr.filter((item, index) arr.indexOf(item) index); // 方法二使用 Set一行解决 const unique2 [...new Set(arr)];两种写法都能得到[1, 2, 3]但性能差距巨大方法时间复杂度filter indexOfO(n²)new Set()O(n)别小看这个差异。当数组长度达到 10000 级别时前者可能卡顿几百毫秒后者几乎无感。但这还不是全部问题。如果数组里存的是对象呢const users [ { id: 1, name: Alice }, { id: 2, name: Bob }, { id: 1, name: Alice } // 重复项 ]; // 你会发现无论 indexOf 还是 includes 都无法识别这两个对象相等 users.includes(users[0]); // true users.includes({ id: 1, name: Alice }); // false因为对象比较的是引用地址内容相同也没用。这个时候Set依然束手无策 —— 它也只能基于引用去重。但我们可以通过封装逻辑配合Map来解决这类需求后文会讲。那 Set 到底是怎么工作的你可以把Set想象成一个“智能盒子”它只允许每个值进去一次。它的底层通常基于哈希表实现插入、查找、删除平均时间复杂度都是O(1)。虽然 V8 引擎内部实现细节很复杂但从行为上我们可以这样抽象添加元素时先检查是否已存在如果不存在则添加并记录顺序所有操作保持插入顺序可遍历。而且Set对NaN友好 —— 尽管NaN ! NaN但在Set中只会保留一个NaN。动手实现一个简易版 Set光说不练假把式。下面我们来手写一个简化但功能完整的MySet类帮助你彻底搞懂它的运行机制。class MySet { constructor(iterable) { this._items []; if (iterable) { for (const item of iterable) { this.add(item); } } } add(value) { if (!this.has(value)) { this._items.push(value); } return this; // 支持链式调用 } has(value) { // 特殊处理 NaN利用 NaN ! NaN 的特性 if (value ! value) { return this._items.some(v v ! v); } return this._items.includes(value); } delete(value) { const index this._items.findIndex(v { // 同样处理 NaN if (v ! v value ! v) return true; return v value; }); if (index -1) { this._items.splice(index, 1); return true; } return false; } clear() { this._items []; } get size() { return this._items.length; } [Symbol.iterator]() { let index 0; return { next: () { if (index this._items.length) { return { value: this._items[index], done: false }; } return { done: true }; } }; } }关键设计点解析has中的value ! value是判断NaN的经典技巧因为只有NaN满足x ! x所以可以用它来做特殊匹配。迭代器协议[Symbol.iterator]让实例支持for...of这是 ES6 可迭代协议的核心让自定义集合也能被原生语法消费。返回this实现链式调用如set.add(1).add(2)提升 API 使用体验。使用数组存储_items是为了教学清晰实际引擎不会这么做includes是 O(n)生产环境多用哈希结构优化。尽管这个版本性能不如原生Set但它完整还原了语义逻辑非常适合学习和调试。MapJavaScript 终于有了真正的字典如果说Set解决了“唯一性”的问题那Map解决的就是“灵活映射”的问题。在 ES6 之前我们只能用普通对象{}来模拟键值对const cache {}; const key someDOMNode; cache[key] data; // ❌ 出问题了为什么出问题因为所有非字符串键都会被自动转成字符串{}.toString(); // [object Object] [] []; // 于是两个不同的对象可能变成同一个键造成数据覆盖。更糟的是原型链上的属性也可能被误读toString in {} // true即使你没定义这就是所谓的“属性名污染”。而Map彻底打破了这些限制。Map 的核心优势对比维度普通对象 ({})Map键类型仅字符串/Symbol任意类型包括对象、函数插入顺序不保证早期 JS 行为不一保证按插入顺序获取大小需Object.keys().length直接.size是否受原型影响是否动态增删性能可能触发隐藏类失效更稳定正因为这些优点Map成为现代 JS 中管理动态映射关系的首选工具。手写实现 MyMap揭开哈希映射的本质同样地我们通过手写MyMap来理解其内部机制。class MyMap { constructor(iterable) { this._items []; if (iterable) { for (const [key, value] of iterable) { this.set(key, value); } } } set(key, value) { const entry this._findEntry(key); if (entry) { entry.value value; } else { this._items.push({ key, value }); } return this; } get(key) { const entry this._findEntry(key); return entry ? entry.value : undefined; } has(key) { return !!this._findEntry(key); } delete(key) { const index this._items.findIndex(entry this._isKeyEqual(entry.key, key) ); if (index -1) { this._items.splice(index, 1); return true; } return false; } clear() { this._items []; } get size() { return this._items.length; } _findEntry(key) { return this._items.find(entry this._isKeyEqual(entry.key, key)); } _isKeyEqual(a, b) { // 处理 NaN NaN if (a ! a b ! b) return true; return a b; } [Symbol.iterator]() { let index 0; return { next: () { if (index this._items.length) { const { key, value } this._items[index]; return { value: [key, value], done: false }; } return { done: true }; } }; } }设计亮点说明_findEntry抽离查找逻辑避免重复代码_isKeyEqual正确处理NaN比较确保语义一致性迭代器返回[key, value]数组符合规范支持解构js for (const [k, v] of myMap) { console.log(k, v); }支持链式调用API 更友好。虽然查找仍是 O(n)但对于小型缓存或配置映射完全够用。更重要的是它揭示了Map的本质一个支持任意键的有序键值对列表。工程实战中的典型应用场景理论懂了怎么用才是关键。以下是我在真实项目中总结的高价值使用模式。场景一用户选中状态管理Setconst selectedIds new Set(); function toggleSelect(id) { selectedIds.has(id) ? selectedIds.delete(id) : selectedIds.add(id); } toggleSelect(1); // 选中 toggleSelect(2); // 再选中 toggleSelect(1); // 取消自动去重生效 console.log([...selectedIds]); // [2]✅ 优势无需手动维护索引天然防重复。场景二DOM 节点元数据绑定Mapconst nodeStyles new Map(); function attachStyle(node, style) { nodeStyles.set(node, style); } function applyStyles() { for (const [node, style] of nodeStyles) { Object.assign(node.style, style); } } // 即使节点被复用也能精准恢复样式 attachStyle(document.getElementById(btn), { color: red });✅ 优势安全附加数据不影响 DOM 结构也不会泄漏全局变量。场景三函数记忆化Memoization优化性能function memoize(fn) { const cache new Map(); return function(...args) { const key args.length 1 ? args[0] : JSON.stringify(args); if (cache.has(key)) { return cache.get(key); } const result fn.apply(this, args); cache.set(key, result); return result; }; } const fib memoize(n n 1 ? n : fib(n - 1) fib(n - 2)); fib(40); // 原本递归爆炸现在瞬间完成⚠️ 注意对于对象参数建议升级为WeakMap避免内存泄漏。高阶技巧与最佳实践1. 什么时候该用SetvsArray元素需唯一 →Set需频繁判断是否存在 →Set.has()比arr.includes()快得多不关心顺序或需要排序 → 仍可用Array2.Mapvs 普通对象怎么选使用场景推荐选择键是字符串且结构固定{}键是变量/对象/函数Map频繁增删键值对Map需要.size或迭代顺序Map3. 内存安全善用WeakSet和WeakMap如果你用对象作为键并希望在对象被回收时自动释放关联数据请使用弱引用版本const seenNodes new WeakSet(); function processNode(node) { if (seenNodes.has(node)) return; seenNodes.add(node); // 处理逻辑... }WeakSet和WeakMap不会阻止垃圾回收适合做标记、缓存、监听等场景。4. 不要试图JSON.stringify(Set)直接序列化会失败JSON.stringify(new Set([1,2,3])); // {}正确做法JSON.stringify([...new Set([1,2,3])]); // [1,2,3]或者转换为对象形式存储。写在最后掌握 Set 与 Map才算真正迈入现代 JS 开发Set和Map看似只是两个新数据结构实则代表了一种思维方式的转变从“将就用对象模拟”到“选用合适的数据模型”。当你开始思考“这个场景该用Set还是Map”、“要不要考虑内存回收”——你就已经脱离了初级编码阶段。它们也是许多高级特性的基石。比如React中用Set管理依赖列表Vue的响应式系统用WeakMap存储观测关系缓存池、事件总线、权限校验等通用模块广泛采用Map未来 ECMAScript 提案中的HashSets、HashTables、甚至Tuple和Record也都延续了这一理念。所以下次你在写去重逻辑时不要再写filter indexOf了。打开控制台敲下[...new Set(array)]那一瞬间的清爽感就是技术进步带来的最小却最真实的快乐。如果你在实际项目中有有趣的Set/Map用法欢迎在评论区分享交流创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

怎么通过网站打广告seo基础知识考试

无需GPU专家!Linly-Talker镜像开箱即用,快速部署 在电商直播间里,一个面容亲切的虚拟主播正流畅地介绍新品;在企业客服页面上,一位数字员工微笑着解答用户疑问——这些曾经需要动辄数十人团队、数月开发周期才能实现的…

张小明 2026/1/10 5:49:22 网站建设

苏州营销网站建设公司怎样把录的视频做一下传到网站

一、项目总览1.1 MES系统建设目的阐述引入MES系统的核心目标,如提升生产效率、优化管理流程、增强质量追溯能力等。1.2 项目实施目标明确项目实施在效率提升、成本降低、质量改进等方面的具体可量化目标。1.3 项目范围界定界定MES系统覆盖的业务范围、涉及的部门与生…

张小明 2026/1/10 5:08:14 网站建设

科技网站导航网站策划书网站需求分析

作为程序员,每天都要面对各种稀奇古怪的bug。最近我发现了一个能极大提升调试效率的工具——Cursor编辑器,特别是它的自动调试功能,简直像是有个编程助手坐在旁边帮你排查问题。初识Cursor的调试能力第一次使用Cursor时,我正被一个…

张小明 2026/1/10 6:45:35 网站建设

百度推广官网网站wordpress去掉域名后缀

概要介绍 多数企业采用 “SAP 专业业务系统” 架构,SAP 负责财账管理,采购、生产等业务由专业系统精细化运营,跨系统物料出入库、收货过账等数据的实时同步已成为业务协同刚需。而 SAP 原生 RFC 接口调用因技术门槛高、开发周期长、运维难度…

张小明 2026/1/10 7:11:21 网站建设

计算机基础网站建设和网络安全天眼查询企业信息官网在线

FaceFusion在城市规划公众参与中的居民形象模拟展示 在一座老城区即将启动改造的社区议事会上,一位年过七旬的居民盯着投影屏上的效果图皱眉:“这楼是挺漂亮,可我怎么觉得这不是我们的家?”——这样的场景,在全国许多…

张小明 2026/1/10 1:15:02 网站建设

常州做网站公司排名设计做任务的网站

收藏和点赞,您的关注是我创作的动力 文章目录概要一、浴室水温控制系统基本原理2.1浴室水温控制系统总体架构2.2浴室水温系统总体设计流程二、浴室水温控制系统硬件设计三、 系统软件设计1附录A 电路图程序四、 总结五、 文章目录概要 基于此种情况,本课…

张小明 2026/1/10 4:57:22 网站建设