ECMAScript 2016 引入了一种新的数据结构——Map,它可以用来存储键值对的集合。相较于传统的对象(Object),Map 具有更多优势,比如键可以是任何类型(包括对象),遍历时按插入顺序,有 size 属性等等。
本文将为大家详细介绍 Map 的用法,并通过示例代码演示如何使用 Map 来解决一些实际问题。
基本用法
Map 的创建和初始化非常简单:
let map = new Map();
我们还可以在创建时添加键值对:
let map = new Map([['key1', 'value1'], ['key2', 'value2']]);
如果需要添加、修改或删除键值对,可以使用 set、get、has、delete、clear 方法:
let map = new Map(); map.set('key1', 'value1'); map.set('key2', 'value2'); map.get('key1'); // 'value1' map.has('key3'); // false map.delete('key1'); map.clear();
Map 的遍历方式有多种,可以使用 for...of 循环或者 forEach 方法:
// javascriptcn.com 代码示例 let map = new Map([['key1', 'value1'], ['key2', 'value2']]); for(let pair of map) { console.log(pair[0], pair[1]); } // 'key1', 'value1' // 'key2', 'value2' map.forEach((value, key) => { console.log(key, value); }); // 'key1', 'value1' // 'key2', 'value2'
实际应用
统计字符出现次数
假设我们有一个字符串,需要统计每个字符出现的次数。使用 Map 可以很方便地解决这个问题:
// javascriptcn.com 代码示例 function countChars(str) { let map = new Map(); for(let char of str) { let count = map.get(char) || 0; map.set(char, count + 1); } return map; } let result = countChars('hello world'); console.log(result); // Map(9) { 'h' => 1, 'e' => 1, 'l' => 3, 'o' => 2, ' ' => 1, 'w' => 1, 'r' => 1, 'd' => 1 }
缓存函数结果
在实际开发中,函数经常需要进行复杂计算,为了避免重复计算,我们可以将已经计算过的结果缓存起来,当下次需要计算相同参数的结果时,直接返回缓存的结果。使用 Map 可以轻松地实现这个功能:
// javascriptcn.com 代码示例 function cached(fn) { let cache = new Map(); return function(...args) { let key = args.join(','); if(cache.has(key)) { console.log('get from cache'); return cache.get(key); } let result = fn(...args); cache.set(key, result); return result; } } function complexCalculation(x, y) { console.log('starting calculation'); return x * y; } let cachedCalculation = cached(complexCalculation); let result = cachedCalculation(2, 3); console.log(result); // 6 result = cachedCalculation(2, 3); console.log(result); // 6 (get from cache) result = cachedCalculation(3, 4); console.log(result); // 12 result = cachedCalculation(3, 4); console.log(result); // 12 (get from cache)
实现 LRU 缓存
LRU(Least Recently Used)缓存是一种常见的缓存策略,基本思想是移除最近不常使用的缓存项。我们可以使用 Map 和双向链表来实现 LRU 缓存:
// javascriptcn.com 代码示例 class LRUMap { constructor(maxSize) { this.maxSize = maxSize; this.map = new Map(); this.head = { key: null, value: null, prev: null, next: null }; this.tail = { key: null, value: null, prev: this.head, next: null }; this.head.next = this.tail; } get(key) { if(!this.map.has(key)) { return null; } let node = this.map.get(key); this.moveToHead(node); return node.value; } set(key, value) { let node = this.map.get(key); if(node) { node.value = value; this.moveToHead(node); } else { if(this.map.size === this.maxSize) { this.removeTail(); } node = { key, value, prev: this.head, next: this.head.next }; this.head.next.prev = node; this.head.next = node; this.map.set(key, node); } } moveToHead(node) { this.removeNode(node); node.prev = this.head; node.next = this.head.next; this.head.next.prev = node; this.head.next = node; } removeNode(node) { node.prev.next = node.next; node.next.prev = node.prev; } removeTail() { let node = this.tail.prev; this.removeNode(node); this.map.delete(node.key); } } let lruMap = new LRUMap(2); lruMap.set('key1', 'value1'); lruMap.set('key2', 'value2'); console.log(lruMap.get('key1')); // 'value1' lruMap.set('key3', 'value3'); console.log(lruMap.get('key1')); // null console.log(lruMap.get('key2')); // 'value2' console.log(lruMap.get('key3')); // 'value3'
总结
Map 是 ECMAScript 2016 中新增的数据结构,具有很多实用的方法和属性,可以解决很多实际问题。本文中介绍了 Map 的基本用法和几个实际应用场景,希望读者能够掌握 Map 的基本用法,并且能够灵活运用 Map 解决实际问题。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6532194d7d4982a6eb44eb84