当前位置: 首页 > article >正文

ES6 Map 数据结构是用总结

1. Map 基本概念

Map 是 ES6 提供的新的数据结构,它类似于对象,但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也可以跟踪键值对的原始插入顺序。

1.1 基本用法

// 创建一个空Map
const map = new Map();

// 创建一个带有初始值的Map
const map1 = new Map([
  ['name', 'John'],
  ['age', 25]
]);

// 使用对象作为键
const objKey = { id: 1 };
const map2 = new Map();
map2.set(objKey, 'value for object');

// Map的大小
console.log(map1.size); // 2

let myMap = new Map();
myMap.set("name", "Alice");
myMap.set(1, "one");
myMap.set(true, "boolean");
console.log(myMap); // Map { 'name' => 'Alice', 1 => 'one', true => 'boolean' }

1.2 Map的基本方法

const map = new Map();

// 添加键值对
map.set('name', 'John');
map.set('age', 25).set('city', 'New York'); // 支持链式调用

// 获取值
console.log(map.get('name')); // 'John'

// 检查键是否存在
console.log(map.has('age')); // true

// 删除键值对
map.delete('age');

// 清空Map
map.clear();

// 获取Map的大小
console.log(map.size); // 0
方法说明
set(key, value)添加键值对
get(key)获取键对应的值
delete(key)删除某个键值对
has(key)判断某个键是否存在
clear()清空 Map
size获取键值对数量
console.log(myMap.get("name")); // Alice
console.log(myMap.has(1)); // true
myMap.delete(true);
console.log(myMap.size); // 2
myMap.clear();
console.log(myMap.size); // 0

2. Map的遍历

2.1 遍历方法

const map = new Map([
  ['name', 'John'],
  ['age', 25],
  ['city', 'New York']
]);

// keys() - 返回键名的遍历器
for (let key of map.keys()) {
  console.log(key);
}

// values() - 返回键值的遍历器
for (let value of map.values()) {
  console.log(value);
}

// entries() - 返回键值对的遍历器
for (let [key, value] of map.entries()) {
  console.log(key, value);
}

// forEach() - 使用回调函数遍历
map.forEach((value, key) => {
  console.log(key, value);
});

let map = new Map([
  ["name", "Alice"],
  ["age", 25],
  ["gender", "female"]
]);

console.log([...map.keys()]); // ['name', 'age', 'gender']
console.log([...map.values()]); // ['Alice', 25, 'female']
console.log([...map.entries()]); // [['name', 'Alice'], ['age', 25], ['gender', 'female']]

2.2 与对象的转换

// Map转对象
function mapToObject(map) {
  const obj = {};
  for (let [key, value] of map) {
    obj[key] = value;
  }
  return obj;
}

// 对象转Map
function objectToMap(obj) {
  return new Map(Object.entries(obj));
}

// 使用示例
const map = new Map([['name', 'John'], ['age', 25]]);
const obj = mapToObject(map);
const backToMap = objectToMap(obj);

3. 实际应用场景

3.1 缓存系统

class Cache {
  constructor() {
    this.cache = new Map();
  }

  set(key, value, ttl = 60000) { // 默认缓存1分钟
    const expires = Date.now() + ttl;
    this.cache.set(key, { value, expires });
  }

  get(key) {
    const data = this.cache.get(key);
    if (!data) return null;
    
    if (Date.now() > data.expires) {
      this.cache.delete(key);
      return null;
    }
    
    return data.value;
  }

  clear() {
    this.cache.clear();
  }
}

// 使用示例
const cache = new Cache();
cache.set('user', { id: 1, name: 'John' }, 5000); // 缓存5秒
console.log(cache.get('user')); // { id: 1, name: 'John' }

3.2 状态管理

class StateManager {
  constructor() {
    this.states = new Map();
    this.listeners = new Map();
  }

  setState(key, value) {
    this.states.set(key, value);
    if (this.listeners.has(key)) {
      this.listeners.get(key).forEach(listener => listener(value));
    }
  }

  getState(key) {
    return this.states.get(key);
  }

  subscribe(key, callback) {
    if (!this.listeners.has(key)) {
      this.listeners.set(key, new Set());
    }
    this.listeners.get(key).add(callback);
  }
}

// 使用示例
const store = new StateManager();
store.subscribe('theme', theme => console.log(`Theme changed to ${theme}`));
store.setState('theme', 'dark'); // 输出: Theme changed to dark

3.3 事件总线

class EventBus {
  constructor() {
    this.events = new Map();
  }

  on(event, callback) {
    if (!this.events.has(event)) {
      this.events.set(event, new Set());
    }
    this.events.get(event).add(callback);
  }

  off(event, callback) {
    if (this.events.has(event)) {
      this.events.get(event).delete(callback);
    }
  }

  emit(event, data) {
    if (this.events.has(event)) {
      this.events.get(event).forEach(callback => callback(data));
    }
  }
}

// 使用示例
const bus = new EventBus();
bus.on('userLogin', user => console.log(`${user.name} logged in`));
bus.emit('userLogin', { name: 'John' }); // 输出: John logged in

3.4 数据结构映射

class BiMap {
  constructor() {
    this.forward = new Map();
    this.reverse = new Map();
  }

  set(key, value) {
    this.forward.set(key, value);
    this.reverse.set(value, key);
  }

  getByKey(key) {
    return this.forward.get(key);
  }

  getByValue(value) {
    return this.reverse.get(value);
  }
}

// 使用示例
const userRoles = new BiMap();
userRoles.set('john', 'admin');
console.log(userRoles.getByKey('john')); // 'admin'
console.log(userRoles.getByValue('admin')); // 'john'

4. WeakMap

WeakMap 是一种特殊的 Map,它只接受对象作为键,并且键是弱引用。

4.1 基本用法

const wm = new WeakMap();
let key = { id: 1 };
wm.set(key, 'value');

console.log(wm.get(key)); // 'value'
key = null; // key对象可被垃圾回收

4.2 实际应用场景

// 使用 WeakMap 存储私有数据
const privateData = new WeakMap();

class User {
  constructor(name, age) {
    privateData.set(this, { name, age });
  }

  getName() {
    return privateData.get(this).name;
  }

  getAge() {
    return privateData.get(this).age;
  }
}

const user = new User('John', 25);
console.log(user.getName()); // 'John'

4.3 Map 与 WeakMap 的区别**

特性MapWeakMap
是否存储值✅ 是✅ 是
是否存储对象✅ 是✅ 仅能存对象
是否支持遍历✅ 是❌ 不能遍历
是否允许自动垃圾回收❌ 否✅ 是

📌 WeakMap 适用于 存储对象的私有数据,对象若被其他变量引用解除,会被自动回收,不会造成内存泄漏。

let weakMap = new WeakMap();
let obj = { name: "John" };
weakMap.set(obj, "privateData");
console.log(weakMap.get(obj)); // privateData
obj = null; // 当对象无引用时会被垃圾回收

5. 性能考虑

5.1 Map vs Object

特性MapObject
键的类型任意类型仅字符串或 Symbol
是否有默认原型❌ 否✅ 是(Object.prototype
遍历顺序按插入顺序无序(ES6 之后部分实现有序)
适合场景需要键值存储,键可为任意类型传统键值对、JSON 结构
// Map 在频繁增删键值对时性能更好
const map = new Map();
const obj = {};

console.time('Map');
for (let i = 0; i < 1000000; i++) {
  map.set(i, i);
  map.delete(i);
}
console.timeEnd('Map');

console.time('Object');
for (let i = 0; i < 1000000; i++) {
  obj[i] = i;
  delete obj[i];
}
console.timeEnd('Object');

let obj = {};
obj["1"] = "one";
obj[1] = "number one";
console.log(obj); // { '1': 'number one' }  因为 Object 的键被转换为字符串

let map = new Map();
map.set("1", "one");
map.set(1, "number one");
console.log(map); // Map { '1' => 'one', 1 => 'number one' }

5.2 内存优化

// 及时清理不需要的数据
function processData(data) {
  const map = new Map();
  // 处理数据...
  map.clear(); // 及时清空释放内存
}

6. 最佳实践

  1. 需要非字符串键时使用 Map
  2. 需要保持键值对顺序时使用 Map
  3. 频繁增删键值对时使用 Map
  4. 存储私有数据时考虑使用 WeakMap
  5. 需要遍历键值对时使用 Map
  6. 注意内存管理,及时清理不需要的数据

http://www.kler.cn/a/536532.html

相关文章:

  • 解释一下数据库中的事务隔离级别,在 Java 中如何通过 JDBC设置事务隔离级别?
  • C# 综合运用介绍
  • 《深度揭秘LDA:开启人工智能降维与分类优化的大门》
  • SMU winter 2025 Personal Round 2
  • Android Studio 2024.2.2.13版本安装配置详细教程
  • 三星OEM版SSD固态硬盘Model码对应关系
  • 讯飞智作 AI 配音技术浅析(三):自然语言处理
  • Kubernetes与Deepseek
  • 二十四、映射类
  • 如何在Linux上安装Ollama
  • 利用ETL工具进行数据挖掘
  • websocket使用
  • JAVA高级工程师-面试经历(含面试问题及解答)
  • k8s节点维护注意事项
  • CVE-2024-13025-Codezips 大学管理系统 faculty.php sql 注入分析及拓展
  • 中国城商行信贷业务数仓建设白皮书(第四期:机器学习中台建设)
  • 多光谱成像技术在华为Mate70系列的应用
  • 蓝耘智算平台搭载DeepSeek R1模型:高效环境配置全攻略
  • 把DeepSeek接入Word软件,给工作提质增效!
  • 《XSS跨站脚本攻击》
  • ChatGPT提问技巧:行业热门应用提示词案例-文案写作
  • 【R】Dijkstra算法求最短路径
  • 记录 | WPF基础学习Style局部和全局调用
  • ubuntu和手机之间如何传递消息
  • Spider 数据集上实现nlp2sql训练任务
  • SpringCloud面试题----SpringCloud和Dubbo有什么区别