登录
首页 >  文章 >  前端

Map.set 链式调用实现状态机映射方法

时间:2026-05-23 08:33:33 294浏览 收藏

本文介绍了如何通过继承原生 Map 并重写 set 等方法,构建一个支持链式调用的 StateMap 类,使其不仅能像普通 Map 一样存储键值对,还能自然融入状态机语义——如 transition 定义状态转移规则、exec 触发带副作用的状态跃迁;结合 WeakMap 还可为每个业务对象(如订单实例)提供隔离、自动回收的专属状态映射,让复杂业务逻辑集中表达、清晰可读、易于测试且无内存泄漏风险。

如何利用 Map.prototype.set() 的链式调用 构建具备状态机特征的业务逻辑映射

Map.prototype.set() 本身不返回 Map 实例,而是返回 undefined,因此**原生不支持链式调用**。但通过简单封装,可以实现兼具状态机语义与链式可读性的业务逻辑映射结构。

为什么直接 set() 无法链式?

标准行为如下:

const map = new Map();
console.log(map.set('a', 1)); // undefined
console.log(map.set('b', 2)); // undefined

每次调用返回 undefined,后续无法继续调用方法。要链式,需让每次操作返回自身(即 Map 实例)。

封装一个支持链式的 StateMap 类

继承原生 Map,重写 set() 和关键方法,使其返回 this

  • 保留所有原生 Map 功能(如 gethasentries
  • set(key, value) 返回 this,支持连续调用
  • 可扩展 on(key, handler)transition(from, to, action) 等状态机语义方法
class StateMap extends Map {
  set(key, value) {
    super.set(key, value);
    return this;
  }
  // 示例:添加状态转移注册能力
  transition(from, to, action) {
    const key = `${from}→${to}`;
    return this.set(key, action);
  }
  // 示例:触发状态迁移
  exec(from, to, ...args) {
    const handler = this.get(`${from}→${to}`);
    return handler && handler(...args);
  }
}

用链式方式构建状态驱动的业务映射

例如订单状态机:待支付 → 已支付 → 已发货 → 已完成,每步附带校验与副作用:

const orderFlow = new StateMap()
  .set('status', 'pending')
  .transition('pending', 'paid', (order) => {
    if (order.amount  {
    if (!order.warehouseReady) throw new Error('库存未就绪');
    order.status = 'shipped';
    updateLogistics(order);
  })
  .transition('shipped', 'completed', (order) => {
    order.status = 'completed';
    issueInvoice(order);
  });

后续只需:orderFlow.exec('pending', 'paid', order),逻辑集中、映射清晰、可测试性强。

进阶:结合 WeakMap 实现实例级状态隔离

避免全局状态污染,为每个业务对象(如订单实例)绑定独立状态机:

  • WeakMap 存储对象 → StateMap 映射
  • 每个订单拥有专属状态流转规则,互不干扰
  • 对象销毁时,WeakMap 自动回收,无内存泄漏风险
const instanceStates = new WeakMap();
function getStateMap(obj) {
  if (!instanceStates.has(obj)) {
    instanceStates.set(obj, new StateMap());
  }
  return instanceStates.get(obj);
}
// 使用
const orderA = { id: 'A' };
getStateMap(orderA)
  .transition('pending', 'paid', () => console.log('A paid'))
  .set('current', 'pending');

今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>