JavaScript系列(10)-- Map数据结构专题
JavaScript Map数据结构专题 🗺️
在前九篇文章中,我们探讨了JavaScript的语言特性、ECMAScript标准、引擎工作原理、数值类型、字符串处理、Symbol类型、Object高级特性、Array高级操作和Set数据结构。今天,让我们深入了解JavaScript中的Map数据结构。Map是ES6引入的一种新的键值对集合,它提供了比普通对象更强大和灵活的特性。
Map基础概念 🌟
💡 小知识:Map是一种键值对的集合,其中的键可以是任何类型(包括对象、函数等),这与普通对象只能使用字符串作为键的限制不同。Map还维护了键值对的插入顺序,这使得它在需要有序数据时特别有用。
Map的创建和基本操作 📊
// 1. Map的创建方式
function mapCreation() {
// 空Map
const map1 = new Map();
// 从数组创建
const map2 = new Map([
['key1', 'value1'],
['key2', 'value2']
]);
// 从对象创建
const obj = { name: '张三', age: 25 };
const map3 = new Map(Object.entries(obj));
// 从其他Map创建
const map4 = new Map(map2);
// 基本操作
map1.set('key', 'value'); // 设置键值对
map1.get('key'); // 获取值
map1.has('key'); // 检查键是否存在
map1.delete('key'); // 删除键值对
map1.clear(); // 清空Map
console.log(map1.size); // 获取大小
}
// 2. Map的迭代
function mapIteration() {
const map = new Map([
['name', '张三'],
['age', 25],
['city', '北京']
]);
// forEach方法
map.forEach((value, key, map) => {
console.log(`${key}: ${value}`);
});
// for...of循环
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
// 获取所有键
const keys = [...map.keys()];
// 获取所有值
const values = [...map.values()];
// 获取所有条目
const entries = [...map.entries()];
}
// 3. Map的键比较
function mapKeyComparison() {
const map = new Map();
// NaN作为键
map.set(NaN, 'value');
map.set(NaN, 'new value'); // 会覆盖之前的值
console.log(map.size); // 1
// +0和-0作为键
map.set(+0, 'zero');
map.set(-0, 'negative zero'); // 被视为相同的键
console.log(map.size); // 1
// 对象作为键
const obj1 = { id: 1 };
const obj2 = { id: 1 };
map.set(obj1, 'object 1');
map.set(obj2, 'object 2');
console.log(map.size); // 2,不同对象被视为不同的键
}
Map的高级操作 🔧
// 1. Map与对象的转换
class MapObjectConverter {
// Map转对象
static mapToObject(map) {
const obj = {};
for (const [key, value] of map) {
if (typeof key === 'string' ||
typeof key === 'number' ||
typeof key === 'symbol') {
obj[key] = value;
}
}
return obj;
}
// 对象转Map
static objectToMap(obj) {
return new Map(Object.entries(obj));
}
// 深度转换
static deepMapToObject(map) {
const obj = {};
for (const [key, value] of map) {
if (typeof key === 'string' ||
typeof key === 'number' ||
typeof key === 'symbol') {
obj[key] = value instanceof Map
? this.deepMapToObject(value)
: value;
}
}
return obj;
}
}
// 2. Map的合并和分割
class MapOperations {
// 合并Maps
static merge(...maps) {
const merged = new Map();
for (const map of maps) {
for (const [key, value] of map) {
merged.set(key, value);
}
}
return merged;
}
// 按条件分割Map
static split(map, predicate) {
const matched = new Map();
const unmatched = new Map();
for (const [key, value] of map) {
if (predicate(key, value)) {
matched.set(key, value);
} else {
unmatched.set(key, value);
}
}
return [matched, unmatched];
}
// 过滤Map
static filter(map, predicate) {
const filtered = new Map();
for (const [key, value] of map) {
if (predicate(key, value)) {
filtered.set(key, value);
}
}
return filtered;
}
}
// 3. Map的函数式操作
class FunctionalMapOperations {
// Map
static map(map, transform) {
const result = new Map();
for (const [key, value] of map) {
result.set(key, transform(value, key));
}
return result;
}
// Reduce
static reduce(map, reducer, initialValue) {
let accumulator = initialValue;
for (const [key, value] of map) {
accumulator = reducer(accumulator, value, key);
}
return accumulator;
}
// Chain operations
static chain(map) {
return {
map: transform => FunctionalMapOperations.chain(
FunctionalMapOperations.map(map, transform)
),
filter: predicate => FunctionalMapOperations.chain(
MapOperations.filter(map, predicate)
),
value: () => map
};
}
}
Map的实际应用 💼
让我们看看Map在实际开发中的一些应用场景:
// 1. 缓存系统
class AdvancedCache {
constructor(maxSize = 1000, maxAge = 3600000) {
this.cache = new Map();
this.maxSize = maxSize;
this.maxAge = maxAge;
}
set(key, value, ttl = this.maxAge) {
if (this.cache.size >= this.maxSize) {
const oldestKey = this.cache.keys().next().value;
this.cache.delete(oldestKey);
}
this.cache.set(key, {
value,
timestamp: Date.now(),
ttl
});
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() - item.timestamp > item.ttl) {
this.cache.delete(key);
return null;
}
return item.value;
}
cleanup() {
const now = Date.now();
for (const [key, item] of this.cache) {
if (now - item.timestamp > item.ttl) {
this.cache.delete(key);
}
}
}
}
// 2. 状态管理系统
class StateManager {
constructor() {
this.states = new Map();
this.listeners = new Map();
}
setState(key, value) {
const oldValue = this.states.get(key);
this.states.set(key, value);
// 通知监听器
if (this.listeners.has(key)) {
this.listeners.get(key).forEach(listener =>
listener(value, oldValue)
);
}
}
getState(key) {
return this.states.get(key);
}
subscribe(key, listener) {
if (!this.listeners.has(key)) {
this.listeners.set(key, new Set());
}
this.listeners.get(key).add(listener);
// 返回取消订阅函数
return () => {
this.listeners.get(key).delete(listener);
};
}
}
// 3. 依赖注入容器
class DIContainer {
constructor() {
this.services = new Map();
this.singletons = new Map();
}
register(name, constructor, dependencies = []) {
this.services.set(name, { constructor, dependencies });
}
registerSingleton(name, constructor, dependencies = []) {
this.register(name, constructor, dependencies);
this.singletons.set(name, null);
}
resolve(name) {
const service = this.services.get(name);
if (!service) {
throw new Error(`Service ${name} not found`);
}
// 检查是否是单例
if (this.singletons.has(name)) {
if (this.singletons.get(name) === null) {
const instance = this.createInstance(service);
this.singletons.set(name, instance);
}
return this.singletons.get(name);
}
return this.createInstance(service);
}
createInstance(service) {
const dependencies = service.dependencies.map(dep =>
this.resolve(dep)
);
return new service.constructor(...dependencies);
}
}
性能优化 ⚡
处理Map时的一些性能优化技巧:
// 1. Map大小优化
function mapSizeOptimization() {
// 预分配合适的大小
const entries = new Array(1000)
.fill(0)
.map((_, i) => [`key${i}`, i]);
// 一次性创建Map
const map = new Map(entries); // 比循环添加更快
// 避免频繁修改
const tempEntries = [];
for (let i = 0; i < 1000; i++) {
tempEntries.push([`key${i}`, i]);
}
const map2 = new Map(tempEntries);
}
// 2. Map操作优化
class OptimizedMapOperations {
// 批量设置优化
static batchSet(map, entries) {
const newMap = new Map(map);
for (const [key, value] of entries) {
newMap.set(key, value);
}
return newMap;
}
// 批量删除优化
static batchDelete(map, keys) {
const newMap = new Map(map);
for (const key of keys) {
newMap.delete(key);
}
return newMap;
}
}
// 3. 内存优化
class MemoryEfficientMap {
constructor() {
this.map = new Map();
this.weakRefs = new WeakMap();
}
set(key, value) {
if (typeof key === 'object' && key !== null) {
const ref = new WeakRef(key);
this.weakRefs.set(key, ref);
this.map.set(ref, value);
} else {
this.map.set(key, value);
}
}
get(key) {
if (typeof key === 'object' && key !== null) {
const ref = this.weakRefs.get(key);
return ref ? this.map.get(ref) : undefined;
}
return this.map.get(key);
}
}
最佳实践建议 💡
- Map使用场景
// 1. 键值对管理
function keyValueManagement() {
// 使用对象作为键
const userMap = new Map();
const userObj = { id: 1, name: '张三' };
userMap.set(userObj, { role: 'admin' });
// 频繁增删键值对
const cacheMap = new Map();
cacheMap.set('key1', 'value1');
cacheMap.delete('key1');
// 需要保持插入顺序
const orderedMap = new Map([
[1, 'first'],
[2, 'second'],
[3, 'third']
]);
}
// 2. 数据关联
function dataAssociation() {
const users = new Map();
const posts = new Map();
// 用户-帖子关联
function associateUserPosts(userId, postId) {
const userPosts = users.get(userId) || new Set();
userPosts.add(postId);
users.set(userId, userPosts);
}
}
// 3. 状态追踪
function stateTracking() {
const stateMap = new Map();
function updateState(key, newState) {
const oldState = stateMap.get(key);
stateMap.set(key, newState);
return [oldState, newState];
}
}
- 错误处理和验证
// 1. Map验证
function validateMap(map) {
if (!(map instanceof Map)) {
throw new TypeError('参数必须是Map类型');
}
if (map.size === 0) {
throw new Error('Map不能为空');
}
return true;
}
// 2. 安全的Map操作
function safeMapOperations() {
function safeGet(map, key, defaultValue = null) {
try {
return map.has(key) ? map.get(key) : defaultValue;
} catch (error) {
console.error('获取值失败:', error);
return defaultValue;
}
}
function safeSet(map, key, value) {
try {
map.set(key, value);
return true;
} catch (error) {
console.error('设置值失败:', error);
return false;
}
}
}
// 3. 类型检查
function mapTypeChecking() {
function isStringKeyMap(map) {
return map instanceof Map &&
[...map.keys()].every(key => typeof key === 'string');
}
function isObjectValueMap(map) {
return map instanceof Map &&
[...map.values()].every(value =>
value && typeof value === 'object'
);
}
}
结语 📝
JavaScript的Map数据结构为我们提供了一种强大的键值对存储方案。我们学习了:
- Map的基本概念和操作
- Map的高级操作和转换
- 实际应用场景
- 性能优化技巧
- 最佳实践和注意事项
💡 学习建议:在选择使用Map还是普通对象时,要考虑具体的使用场景。如果需要非字符串类型的键、需要保持插入顺序,或者需要频繁增删键值对,Map是更好的选择。同时,要注意Map的内存使用和性能优化。
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻