Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/427.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript中的不可变和集合_Javascript_Arrays_Immutable Collections - Fatal编程技术网

JavaScript中的不可变和集合

JavaScript中的不可变和集合,javascript,arrays,immutable-collections,Javascript,Arrays,Immutable Collections,我正试图弄清楚如何在JavaScript/TypeScript中使用不可变项,而不用花一整天的时间。我还没有完全准备好深入到Immutable.js中,因为就类型安全性而言,它似乎会让您无所适从 让我们举一个例子,我有一个数组,其中的元素都是MyType类型。在我的类中,我有一个方法搜索数组并返回匹配元素的副本,这样我们就不会编辑原始元素。现在说,以后我需要查看对象是否在数组中,但我拥有的是副本,而不是原件 处理这个问题的标准方法是什么?我能想到的任何确定我是否已经拥有该项的方法都将采取某种形式

我正试图弄清楚如何在JavaScript/TypeScript中使用不可变项,而不用花一整天的时间。我还没有完全准备好深入到Immutable.js中,因为就类型安全性而言,它似乎会让您无所适从

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

处理这个问题的标准方法是什么?我能想到的任何确定我是否已经拥有该项的方法都将采取某种形式,在集合中循环,访问每个元素,然后进行笨拙的相等匹配,无论是将它们都转换为字符串还是使用第三方库


我想使用不可变的,但我经常遇到这样的情况,使它们看起来很不吸引人。我遗漏了什么?

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

您写道您有一个方法“…返回匹配元素的副本,这样我们就不会编辑原始元素”。您能否更改该方法,使其同时返回原始和副本

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

我不知道这是否违反了其他不变性最佳实践,例如,保留对元素的引用副本(我想,这会让代码在将来违反不变性,即使它们目前没有被违反……尽管您可以使用原始代码来防止将来的突变)。然而,它至少允许您在技术上保持所有内容不变的同时仍然能够通过引用进行搜索。因此,您可以根据需要对克隆进行任意变异,但仍然可以通过引用原始副本来保留关联副本

const retrieveDerivative=(数组,elmtNum)=>{
常数=数组[elmtNum];
const clone=JSON.parse(JSON.stringify(orig));
返回{orig,clone};
};
常量getIndexOfElmt=(数组,派生元素)=>{
返回数组.indexOf(DerivativeFelement.orig);
};
常量obj1={a:{b:1}};//对象是不相关的。
常量obj3={a:{b:1}};//请注意,所有对象都是相同的
常量obj5={a:{b:1}};//根据价值,因此只能
常量obj8={a:{b:1}};//通过参照区分。
常量myArr=[obj3,obj5,obj1,obj8];
const derivedfromomeelmt=检索派生(myArr,2);
const indexOfSomeElmt=getIndexOfElmt(myArr,派生自someelmt);

console.log(indexOfSomeElmt)您描述的情况是,可变数据结构具有明显的优势,但如果您从使用不可变数据结构中获益,则有更好的方法

保持不变意味着新更新的对象是全新的,这两种方式都适用:您可能有一个新对象,但您仍然可以访问原始对象!你可以用它做很多整洁的事情,例如,链接你的对象,这样你就有了一个撤销历史,并且可以及时返回以回滚更改

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

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

在数组中不返回该对象的副本。您将返回该对象。如果您以后需要对其进行变异,您可以使用所需的更改创建一个副本。假设数组中的对象是不可变的,为什么要创建它的副本?这样一来,客户端代码就有责任正确使用它得到的对象,这似乎是不明智的。这是我自己的项目,所以这当然是我打开的一个选项,但在一个有多个开发人员的大型项目上,这似乎不是一个好主意。如果你想解决类型安全问题,JavaScript没有配备,没有库可以帮助你。不过,您可以使用Typescript或带有注释的静态类型检查器。你可以使用Immuatable.js来处理它们。@AmyBlankenship然后
Object.freeze
如果你不信任它们,就冻结它:-)是的,我想弄清楚这一点,因为Angular 2非常依赖RxJS,不接受Immutables会让你有一种混乱的方法,但我很难对在何处使用和在何处不使用它形成直觉(感觉好像没有在任何地方使用它仍然会留下混乱)。就我个人而言,我会说,假设您希望它是不变的,除非某些东西可能非常大(内存中为100MB以上),或者存在大量数据模型依赖性(你的只是一个小例子,但是如果你