1

我试图弄清楚如何在 JavaScript/TypeScript 中使用 Immutables 而无需花一整天的时间。我还没有准备好深入研究 Immutable.js,因为就类型安全而言,它似乎让你感到兴奋和干燥。

所以让我们举一个例子,我有一个数组,其中元素都是 MyType 类型。在我的类中,我有一个搜索数组并返回匹配元素副本的方法,因此我们不会编辑原始元素。现在说,稍后我需要查看对象是否在 Array 中,但我拥有的是副本,而不是原始对象。

处理这个的标准方法是什么?我能想到的任何方法来确定我是否已经拥有这个项目将采取某种形式的循环遍历集合并访问每个元素,然后进行笨拙的相等匹配,无论是将它们都变成字符串还是使用第三个 -党图书馆。

我想使用 Immutables,但我经常遇到这样的情况,这让它们看起来很没有吸引力。我错过了什么?

4

2 回答 2

1

我怀疑我的解决方案不是“……处理这个问题的标准方法”。但是,我认为这至少是一种做我认为你所要求的方式。

您写道,您有一个“...返回匹配元素的副本,因此我们不会编辑原始元素”的方法。你能改变那个方法,让它同时返回原件副本吗?

例如,下面的策略涉及从数组中检索原始元素(稍后可用于通过引用进行搜索)以及克隆(可以根据需要对其进行操作而不会影响原始元素)。在检索过程中克隆原件仍有成本,但至少在以后搜索数组时不必对数组中的每个元素进行此类转换。此外,它甚至允许您区分按值相同的数组元素,如果您最初只检索元素的副本,这是不可能的。下面的代码通过使每个数组元素按值相同(但根据对象的定义,按引用不同)来演示这一点。

我不知道这是否违反了其他不变性最佳实践,例如,保留对元素的引用的副本(我想,这会使代码对未来的不变性违反开放,即使它们当前没有被违反......尽管你可以深度冻结原始文件以防止将来发生突变)。但是,它至少允许您在技术上保持所有内容不可变,同时仍然能够通过引用进行搜索。因此,您可以随心所欲地对您的克隆进行变异,但仍始终保留原始的相关联的按引用复制。

const retrieveDerivative = (array, elmtNum) => {
  const orig = array[elmtNum];
  const clone = JSON.parse(JSON.stringify(orig));
  return {orig, clone};
};

const getIndexOfElmt = (array, derivativeOfElement) => {
  return array.indexOf(derivativeOfElement.orig);
};


const obj1 = {a: {b: 1}}; // Object #s are irrelevant.
const obj3 = {a: {b: 1}}; // Note that all objects are identical
const obj5 = {a: {b: 1}}; // by value and thus can only be
const obj8 = {a: {b: 1}}; // differentiated by reference.

const myArr = [obj3, obj5, obj1, obj8];

const derivedFromSomeElmt = retrieveDerivative(myArr, 2);

const indexOfSomeElmt = getIndexOfElmt(myArr, derivedFromSomeElmt);

console.log(indexOfSomeElmt);

于 2017-02-16T01:30:18.963 回答
1

您所描述的情况是可变数据结构具有明显优势的情况,但如果您从使用不可变数据中受益,那么还有更好的方法。

虽然保持它不可变意味着您的新更新对象是全新的,但这是双向的:您可能有一个新对象,但您仍然可以访问原始对象!你可以用它做很多巧妙的事情,例如链接你的对象,这样你就有一个撤销历史,并且可以及时回滚以回滚更改。

所以不要在数组中使用一些 hacky 的查找属性。您的示例的问题是因为您在错误的时间构建了一个新对象:没有函数返回该对象的副本。让函数返回原始对象,并使用原始对象作为索引调用您的更新。

let myThings = [new MyType(), new MyType(), new MyType()];

// We update by taking the thing, and replacing with a new one.
// I'll keep the array immutable too
function replaceThing(oldThing, newThing) {
  const oldIndex = myThings.indexOf(oldThing);
  myThings = myThings.slice();
  myThings[oldIndex] = newThing;
  return myThings;
}

// then when I want to update it
// Keep immutable by spreading
const redThing = myThings.find(({ red }) => red);
if (redThing) {
  // In this example, there is a 'clone' method
  replaceThing(redThing, Object.assign(redThing.clone(), {
    newProperty: 'a new value in my immutable!',
  });
}

话虽如此,类也使这变得更加复杂。保持简单对象不可变要容易得多,因为您可以简单地将旧对象传播到新对象中,例如{ ...redThing, newProperty: 'a new value' }. 一旦你得到一个高于 1 的对象,你可能会发现 immutable.js 更有用,因为你可以mergeDeep.

于 2017-02-16T01:58:34.727 回答