javascript - 如何在没有突变的情况下使用 javascript Map

标签 javascript dictionary functional-programming immutability

我在我的 JS 项目中以一种功能性的方式工作。
这也意味着我不会变异 objectarray实体。相反,我总是创建一个新实例并替换一个旧实例。
例如

let obj = {a: 'aa', b: 'bb'}
obj = {...obj, b: 'some_new_value'}
问题是:
如何使用 javascript Maps 以功能(不可变)方式工作?
我想我可以使用以下代码来添加值:
let map = new Map()
...
map = new Map(map).set(something)
但是删除项目呢?
我做不到new Map(map).delete(something) , 因为 .delete 的结果是一个 bool 值。
附: 我知道 ImmutableJS 的存在,但我不想使用它,因为您永远无法 100% 确定您现在使用的是普通的 JS 对象还是 immutablejs 的对象(尤其是嵌套结构)。而且由于对 TypeScript 的支持不好,顺便说一句。

最佳答案

如果您不想使用持久映射数据结构,那么您将无法绕过突变,或者必须进行效率极低的浅拷贝。请注意,突变本身无害,但仅与共享底层可变值一起使用。
如果我们能够限制访问可变值的方式,我们可以获得安全的可变数据类型。不过,它们是有代价的。你不能像往常一样使用它们。事实上,使用它们需要一些时间来熟悉。这是一个权衡。
这是一个带有原生 Map 的示例:

// MUTABLE

const Mutable = clone => refType => // strict variant
  record(Mutable, app(([o, initialCall, refType]) => {
    o.mutable = {
      run: k => {
        o.mutable.run = _ => {
          throw new TypeError("illegal subsequent inspection");
        };

        o.mutable.set = _ => {
          throw new TypeError("illegal subsequent mutation");
        };

        return k(refType);
      },

      set: k => {
        if (initialCall) {
          initialCall = false;
          refType = clone(refType);
        }

        k(refType);
        return o;
      }
    }

    return o;
  }) ([{}, true, refType]));
  
const mutRun = k => o =>
  o.mutable.run(k);

const mutSet = k => o =>
  o.mutable.set(k);

// MAP

const mapClone = m => new Map(m);

const mapDelx = k => m => // safe-in-place-update variant
  mutSet(m_ =>
    m_.has(k)
      ? m_.delete(k)
      : m_) (m);
      
const mapGet = k => m =>
  m.get(k);

const mapSetx = k => v => // safe-in-place-update variant
  mutSet(m_ => m_.set(k, v));

const mapUpdx = k => f => // safe-in-place-update variant
  mutSet(m_ => m_.set(k, f(m_.get(k))));

const MutableMap = Mutable(mapClone);

// auxiliary functions

const record = (type, o) => (
  o[Symbol.toStringTag] = type.name || type, o);

const app = f => x => f(x);

const id = x => x;

// MAIN

const m = MutableMap(new Map([[1, "foo"], [2, "bar"], [3, "baz"]]));

mapDelx(2) (m);
mapUpdx(3) (s => s.toUpperCase()) (m);

const m_ = mutRun(Array.from) (m);
console.log(m_); // [[1, "foo"], [3, "BAZ"]]

try {mapSetx(4) ("bat") (m)} // illegal subsequent mutation
catch (e) {console.log(e.message)}

try {mutRun(mapGet(1)) (m)} // illegal subsequent inspection
catch (e) {console.log(e.message)}

如果你仔细看看 Mutable您会看到它也创建了一个浅拷贝,但最初只创建一次。然后,您可以根据需要进行尽可能多的突变,直到您第一次检查可变值。
您可以在我的 scriptum library 中找到具有多个实例的实现。 .这是 post以及有关该概念的更多背景信息。
我从 Rust 借用了这个概念,它被称为所有权。类型理论背景是仿射类型,如果您有兴趣,可以将其归入线性类型。

关于javascript - 如何在没有突变的情况下使用 javascript Map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65594804/

相关文章:

xml - 使用 ocaml 创建 xml 文档

javascript - 如何使用 JavaScript 根据用户输入的值检查数组值?

javascript - youtube 播放器 api - 未创建视频播放列表

javascript - div1和div2在同一行时隐藏连接线

c# - 在包含字典的类上公开 foreach

python获取每个键的唯一值计数和键中值的唯一计数

haskell - 依赖类约束的不明确类型变量

javascript - 简单的Javascript下拉框启用问题

python - 将字典转换为元组排序列表

haskell - 如果 (*>) 或 (<*) 丢弃了第一个或第二个参数,为什么还需要这些函数?