映射接口
概述
Map
是键值对集合,提供高效的查找、插入和删除操作。在KubeJS中常用于缓存数据、配置管理、索引构建等场景。
Map特性
- 键值对存储: 每个键关联一个值
- 快速查找: O(1)平均时间复杂度
- 无重复键: 键必须唯一
- 任意类型: 键和值可以是任意类型
基础操作
创建和基本方法
js
/**
* Map基础操作
*/
function mapBasicOperations() {
// 创建Map
const itemMap = new Map();
const configMap = new Map([
['spawn_protection', 16],
['max_players', 20],
['difficulty', 'normal']
]);
// 设置键值对
itemMap.set('minecraft:stone', { count: 64, durability: 100 });
itemMap.set('minecraft:diamond', { count: 16, durability: 1561 });
// 获取值
const stoneData = itemMap.get('minecraft:stone');
const maxPlayers = configMap.get('max_players');
// 检查键是否存在
const hasStone = itemMap.has('minecraft:stone');
const hasGold = itemMap.has('minecraft:gold_ingot');
// 删除键值对
itemMap.delete('minecraft:stone');
// 获取大小
const size = itemMap.size;
// 清空Map
itemMap.clear();
console.log(`石头数据: ${JSON.stringify(stoneData)}`);
console.log(`最大玩家数: ${maxPlayers}`);
console.log(`Map大小: ${size}`);
}
遍历操作
js
/**
* Map遍历方法
* @param {Map} map
*/
function mapIteration(map) {
// 方法1: forEach遍历
map.forEach((value, key) => {
console.log(`${key}: ${value}`);
});
// 方法2: for-of遍历条目
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
// 方法3: 遍历键
for (const key of map.keys()) {
console.log(`键: ${key}`);
}
// 方法4: 遍历值
for (const value of map.values()) {
console.log(`值: ${value}`);
}
// 方法5: 遍历条目
for (const entry of map.entries()) {
console.log(`条目: ${entry[0]} = ${entry[1]}`);
}
}
高级操作
Map转换和操作
js
/**
* Map转换操作
* @param {Map} map
*/
function mapTransformations(map) {
// Map转换为数组
const keysArray = Array.from(map.keys());
const valuesArray = Array.from(map.values());
const entriesArray = Array.from(map.entries());
// Map转换为对象
const mapToObject = Object.fromEntries(map);
// 对象转换为Map
const objectToMap = new Map(Object.entries({
a: 1,
b: 2,
c: 3
}));
// 过滤Map
function filterMap(map, predicate) {
const filtered = new Map();
for (const [key, value] of map) {
if (predicate(key, value)) {
filtered.set(key, value);
}
}
return filtered;
}
// 映射Map值
function mapValues(map, mapper) {
const mapped = new Map();
for (const [key, value] of map) {
mapped.set(key, mapper(value, key));
}
return mapped;
}
// 映射Map键
function mapKeys(map, mapper) {
const mapped = new Map();
for (const [key, value] of map) {
mapped.set(mapper(key, value), value);
}
return mapped;
}
// 使用示例
const numbers = new Map([
['one', 1],
['two', 2],
['three', 3],
['four', 4]
]);
// 过滤偶数
const evenNumbers = filterMap(numbers, (key, value) => value % 2 === 0);
// 值乘以10
const multiplied = mapValues(numbers, value => value * 10);
console.log('偶数:', evenNumbers);
console.log('乘以10:', multiplied);
}
实际应用
缓存系统
js
/**
* 缓存管理系统
*/
class CacheManager {
constructor(maxSize = 100, ttl = 300000) { // 5分钟TTL
this.cache = new Map();
this.timestamps = new Map();
this.maxSize = maxSize;
this.ttl = ttl;
}
// 设置缓存
set(key, value) {
// 清理过期缓存
this.cleanup();
// 如果超过最大大小,删除最旧的
if (this.cache.size >= this.maxSize) {
this.evictOldest();
}
this.cache.set(key, value);
this.timestamps.set(key, Date.now());
}
// 获取缓存
get(key) {
if (!this.cache.has(key)) {
return null;
}
// 检查是否过期
const timestamp = this.timestamps.get(key);
if (Date.now() - timestamp > this.ttl) {
this.cache.delete(key);
this.timestamps.delete(key);
return null;
}
return this.cache.get(key);
}
// 检查缓存存在
has(key) {
return this.get(key) !== null;
}
// 删除缓存
delete(key) {
this.cache.delete(key);
this.timestamps.delete(key);
}
// 清空缓存
clear() {
this.cache.clear();
this.timestamps.clear();
}
// 清理过期缓存
cleanup() {
const now = Date.now();
const expiredKeys = [];
for (const [key, timestamp] of this.timestamps) {
if (now - timestamp > this.ttl) {
expiredKeys.push(key);
}
}
expiredKeys.forEach(key => {
this.cache.delete(key);
this.timestamps.delete(key);
});
}
// 驱逐最旧的缓存
evictOldest() {
let oldestKey = null;
let oldestTime = Infinity;
for (const [key, timestamp] of this.timestamps) {
if (timestamp < oldestTime) {
oldestTime = timestamp;
oldestKey = key;
}
}
if (oldestKey) {
this.delete(oldestKey);
}
}
// 获取缓存统计
getStats() {
return {
size: this.cache.size,
maxSize: this.maxSize,
hitRate: this.hitCount / (this.hitCount + this.missCount) || 0
};
}
}
// 使用示例
const cache = new CacheManager(50, 60000); // 50个条目,1分钟TTL
cache.set('player_data_123', { name: 'Player', level: 50 });
const playerData = cache.get('player_data_123');
console.log('玩家数据:', playerData);
配置管理
js
/**
* 配置管理系统
*/
class ConfigManager {
constructor() {
this.configs = new Map();
this.defaults = new Map();
this.listeners = new Map();
}
// 设置默认值
setDefault(key, value) {
this.defaults.set(key, value);
// 如果没有设置值,使用默认值
if (!this.configs.has(key)) {
this.configs.set(key, value);
}
}
// 设置配置
set(key, value) {
const oldValue = this.configs.get(key);
this.configs.set(key, value);
// 触发监听器
this.notifyListeners(key, value, oldValue);
}
// 获取配置
get(key, defaultValue = null) {
if (this.configs.has(key)) {
return this.configs.get(key);
}
if (this.defaults.has(key)) {
return this.defaults.get(key);
}
return defaultValue;
}
// 获取数字配置
getNumber(key, defaultValue = 0) {
const value = this.get(key, defaultValue);
return typeof value === 'number' ? value : Number(value) || defaultValue;
}
// 获取布尔配置
getBoolean(key, defaultValue = false) {
const value = this.get(key, defaultValue);
return typeof value === 'boolean' ? value : Boolean(value);
}
// 获取字符串配置
getString(key, defaultValue = '') {
const value = this.get(key, defaultValue);
return String(value);
}
// 添加配置监听器
addListener(key, listener) {
if (!this.listeners.has(key)) {
this.listeners.set(key, []);
}
this.listeners.get(key).push(listener);
}
// 移除监听器
removeListener(key, listener) {
if (this.listeners.has(key)) {
const listeners = this.listeners.get(key);
const index = listeners.indexOf(listener);
if (index > -1) {
listeners.splice(index, 1);
}
}
}
// 通知监听器
notifyListeners(key, newValue, oldValue) {
if (this.listeners.has(key)) {
this.listeners.get(key).forEach(listener => {
try {
listener(newValue, oldValue, key);
} catch (error) {
console.error('配置监听器错误:', error);
}
});
}
}
// 批量设置
setAll(configObject) {
Object.entries(configObject).forEach(([key, value]) => {
this.set(key, value);
});
}
// 获取所有配置
getAll() {
return Object.fromEntries(this.configs);
}
// 重置为默认值
reset(key = null) {
if (key) {
if (this.defaults.has(key)) {
this.set(key, this.defaults.get(key));
} else {
this.configs.delete(key);
}
} else {
this.configs.clear();
this.defaults.forEach((value, key) => {
this.configs.set(key, value);
});
}
}
}
// 使用示例
const config = new ConfigManager();
// 设置默认配置
config.setDefault('max_players', 20);
config.setDefault('spawn_protection', 16);
config.setDefault('enable_pvp', true);
// 添加监听器
config.addListener('max_players', (newValue, oldValue) => {
console.log(`最大玩家数从 ${oldValue} 变更为 ${newValue}`);
});
// 设置配置
config.set('max_players', 30);
console.log('最大玩家数:', config.getNumber('max_players'));
索引和查找
js
/**
* 多索引数据管理
*/
class MultiIndexMap {
constructor() {
this.data = new Map();
this.indexes = new Map();
}
// 添加索引
addIndex(indexName, keyExtractor) {
this.indexes.set(indexName, {
keyExtractor: keyExtractor,
index: new Map()
});
// 为现有数据建立索引
for (const [id, item] of this.data) {
this.updateIndex(indexName, id, item);
}
}
// 设置数据
set(id, item) {
// 如果是更新,先清理旧索引
if (this.data.has(id)) {
this.removeFromAllIndexes(id);
}
this.data.set(id, item);
// 更新所有索引
for (const indexName of this.indexes.keys()) {
this.updateIndex(indexName, id, item);
}
}
// 获取数据
get(id) {
return this.data.get(id);
}
// 删除数据
delete(id) {
if (this.data.has(id)) {
this.removeFromAllIndexes(id);
this.data.delete(id);
}
}
// 通过索引查找
findByIndex(indexName, key) {
const indexData = this.indexes.get(indexName);
if (!indexData) return [];
const ids = indexData.index.get(key) || [];
return ids.map(id => this.data.get(id)).filter(item => item !== undefined);
}
// 更新索引
updateIndex(indexName, id, item) {
const indexData = this.indexes.get(indexName);
if (!indexData) return;
const key = indexData.keyExtractor(item);
if (!indexData.index.has(key)) {
indexData.index.set(key, []);
}
const ids = indexData.index.get(key);
if (!ids.includes(id)) {
ids.push(id);
}
}
// 从所有索引中移除
removeFromAllIndexes(id) {
const item = this.data.get(id);
if (!item) return;
for (const [indexName, indexData] of this.indexes) {
const key = indexData.keyExtractor(item);
const ids = indexData.index.get(key);
if (ids) {
const index = ids.indexOf(id);
if (index > -1) {
ids.splice(index, 1);
if (ids.length === 0) {
indexData.index.delete(key);
}
}
}
}
}
// 获取统计信息
getStats() {
const indexStats = {};
for (const [indexName, indexData] of this.indexes) {
indexStats[indexName] = {
keyCount: indexData.index.size,
averageItemsPerKey: this.data.size / indexData.index.size || 0
};
}
return {
totalItems: this.data.size,
indexes: indexStats
};
}
}
// 使用示例:玩家数据管理
const playerManager = new MultiIndexMap();
// 添加索引
playerManager.addIndex('byLevel', player => Math.floor(player.level / 10)); // 按等级段
playerManager.addIndex('byClass', player => player.class); // 按职业
playerManager.addIndex('byGuild', player => player.guild); // 按公会
// 添加玩家数据
playerManager.set('player1', {
name: 'Alice',
level: 25,
class: 'warrior',
guild: 'Dragons'
});
playerManager.set('player2', {
name: 'Bob',
level: 32,
class: 'mage',
guild: 'Dragons'
});
// 查找数据
const level20Players = playerManager.findByIndex('byLevel', 2); // 20-29级
const warriors = playerManager.findByIndex('byClass', 'warrior');
const dragonMembers = playerManager.findByIndex('byGuild', 'Dragons');
console.log('20-29级玩家:', level20Players);
console.log('战士:', warriors);
console.log('龙族公会成员:', dragonMembers);
Map工具类
js
/**
* Map工具类
*/
class MapUtils {
/**
* 合并多个Map
*/
static merge(...maps) {
const result = new Map();
maps.forEach(map => {
for (const [key, value] of map) {
result.set(key, value);
}
});
return result;
}
/**
* Map交集
*/
static intersection(map1, map2) {
const result = new Map();
for (const [key, value] of map1) {
if (map2.has(key)) {
result.set(key, value);
}
}
return result;
}
/**
* Map差集
*/
static difference(map1, map2) {
const result = new Map();
for (const [key, value] of map1) {
if (!map2.has(key)) {
result.set(key, value);
}
}
return result;
}
/**
* 反转Map(值变键,键变值)
*/
static invert(map) {
const result = new Map();
for (const [key, value] of map) {
result.set(value, key);
}
return result;
}
/**
* 按值排序
*/
static sortByValue(map, compareFn = null) {
const entries = Array.from(map.entries());
entries.sort((a, b) => {
if (compareFn) {
return compareFn(a[1], b[1]);
}
return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0;
});
return new Map(entries);
}
/**
* 按键排序
*/
static sortByKey(map, compareFn = null) {
const entries = Array.from(map.entries());
entries.sort((a, b) => {
if (compareFn) {
return compareFn(a[0], b[0]);
}
return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;
});
return new Map(entries);
}
/**
* 获取Map的子集
*/
static subset(map, keys) {
const result = new Map();
keys.forEach(key => {
if (map.has(key)) {
result.set(key, map.get(key));
}
});
return result;
}
/**
* 计数器Map(用于统计)
*/
static createCounter(items, keyExtractor = item => item) {
const counter = new Map();
items.forEach(item => {
const key = keyExtractor(item);
counter.set(key, (counter.get(key) || 0) + 1);
});
return counter;
}
/**
* 分组Map
*/
static groupBy(items, keyExtractor) {
const groups = new Map();
items.forEach(item => {
const key = keyExtractor(item);
if (!groups.has(key)) {
groups.set(key, []);
}
groups.get(key).push(item);
});
return groups;
}
}
// 使用示例
const map1 = new Map([['a', 1], ['b', 2]]);
const map2 = new Map([['b', 3], ['c', 4]]);
const merged = MapUtils.merge(map1, map2);
console.log('合并后:', merged);
const items = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const counter = MapUtils.createCounter(items);
console.log('计数器:', counter);
性能和最佳实践
性能对比
js
/**
* Map vs Object 性能对比
*/
function mapVsObjectPerformance() {
console.log(`
Map vs Object 性能对比:
插入性能:
- Map: O(1) 平均
- Object: O(1) 平均
查找性能:
- Map: O(1) 平均
- Object: O(1) 平均
删除性能:
- Map: O(1) 平均
- Object: O(1) 但可能触发属性重排
遍历性能:
- Map: for-of 最快
- Object: Object.keys() + for循环
内存使用:
- Map: 略高,但更可预测
- Object: 略低,但存在隐藏类优化
使用建议:
- 频繁增删:优选Map
- 简单配置:可用Object
- 非字符串键:必须用Map
- 需要遍历顺序:优选Map
`);
}
/**
* Map性能优化技巧
*/
function mapOptimization() {
// 1. 预设容量(JavaScript Map没有直接方法,但可以批量初始化)
const largeMap = new Map();
const initialData = Array.from({ length: 1000 }, (_, i) => [`key${i}`, i]);
initialData.forEach(([key, value]) => largeMap.set(key, value));
// 2. 使用合适的键类型
const stringKeyMap = new Map(); // 字符串键
const numberKeyMap = new Map(); // 数字键
const objectKeyMap = new Map(); // 对象键(注意内存泄漏)
// 3. 及时清理不需要的键
function cleanupMap(map, isExpired) {
const keysToDelete = [];
for (const [key, value] of map) {
if (isExpired(key, value)) {
keysToDelete.push(key);
}
}
keysToDelete.forEach(key => map.delete(key));
}
// 4. 批量操作比单个操作效率高
function batchSet(map, entries) {
entries.forEach(([key, value]) => map.set(key, value));
}
// 5. 使用WeakMap避免内存泄漏(适用于对象键)
const weakMap = new WeakMap();
console.log('Map性能优化完成');
}