为什么forEach更改其他已过滤的数组

时间:2018-04-02 09:16:45

标签: javascript



var arr = [{a: "one", b: "two"}];
/* in real code I have actual filter condition, but the filtered result
share some common properties with value */
var res = {
  arr1: arr.filter(x => x),
  arr2: arr.filter(x => x)
};

res.arr1.forEach(x => x.a = "a");

console.log(arr); //should print [{a: "one", b: "two"}]
console.log(res.arr1); //should print [{a: "a", b: "two"}]
console.log(res.arr2); //should print [{a: "one", b: "two"}]




如果我更改对象arr1的{​​{1}}数组中的值,那么为什么更改也应用于resarr2res创建新数组,然后不应用效果。

我在这里做错了什么?

4 个答案:

答案 0 :(得分:5)

新数组中的每个元素都保留相同的对象引用,因此您需要克隆该对象。如果没有嵌套值,则可以使用Object.assignArray#map方法。要进行更深入的克隆,您需要使用其他库或需要实现自己的自定义函数。



static const




仅供参考: What is the most efficient way to deep clone an object in JavaScript?

答案 1 :(得分:1)

原因是数组包含对象的引用,而不是它们的副本。因此,虽然filter确实返回一个新数组,但它们内部的对象仍然引用相同的对象。

因此,当forEach改变res.arr1中引用的对象时,它正在修改所有数组中的对象,因为它们都指向相同的引用。

希望这有帮助。

答案 2 :(得分:0)

数组中的项目是对象 - 它们是引用类型。意味着您只有一个对象,而休止符是对同一个对象的引用。因此,从一个引用更改它会影响另一个引用的结果读取。您需要从阵列中复制<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/layout5" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is the text"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="last checking text"/> </LinearLayout> s。在这里,我使用property spreading来复制对象。

&#13;
&#13;
item
&#13;
&#13;
&#13;

答案 3 :(得分:0)

当你写:

xs = [
  { p : true },
  { p : false }
];
ys = xs.filter(
  x => x.p
);

以下是它在内存中的样子:

xs         { p : false }
  \       /
   [ 0 , 1 ]
      \
       { p : true }
      /
   [ 0 ]
  /
ys

正如您所说,.filter()创建了一个新数组,这就是xsys链接到不同数组的原因。然后,由于xs[0].p为真,它会复制xs[0]并将其推送到新数组。您需要在此处实现的是xs[0]{ p : true }的链接,它不是对象本身,而ys[0]是此链接的副本。因此,xs[0]ys[0]链接到同一个对象,如果您撰写xs[0].p = false,则可以使用ys[0].p阅读更新。

xs[0]
     \
      { p : false }
     /
ys[0]

如果你想避免这种情况,你必须复制对象本身:

function copy (x) {
  var y = {}; // new object
  for (var k in x) y[k] = x[k];
  return y;
}
ys[0] = copy(ys[0]);

由于copy()会返回一个新对象,xs[0]ys[0]现在会链接到不同的对象,因此,对一个对象的更改不会影响另一个对象:

xs[0].p = true;
xs[0] --- { p : true }

ys[0] --- { p : false }

关于您的代码,arr[0]{ a: "one", b: "two" }的链接,.filter()创建新数组,其中包含指向同一对象的此链接的副本:

res.arr1[0]
           \
            \
arr[0] ----- { a: "one", b: "two" }
            /
           /
res.arr2[0]

同样,如果你想避免这种情况,你必须复制对象本身。但是,由于arr可能包含多个对象,因此必须遍历数组以逐个复制每个对象。 .map()非常适合这项工作:

res.arr1 = arr.filter(f).map(copy);
res.arr2 = arr.filter(f).map(copy);
res.arr1[0] --- { a: "one", b: "two" }

arr[0] -------- { a: "one", b: "two" }

res.arr2[0] --- { a: "one", b: "two" }

但要小心,对于嵌套对象来说,它有点棘手:

xs = [{ p: {} }]; // nested objects
ys = [copy(xs[0])];

在上述情况中,xs[0]ys[0]不同,但xs[0].pys[0].p相同:

xs[0]
     \
      { p }
         \
          {}
         /
      { p }
     /
ys[0]

在这种情况下,您必须制作对象的深层副本。这个功能可以解决这个问题:

function copyTree (x) {
  if (x instanceof Array) {
    var copy = [];
    for (var i = 0; i < x.length; i++) {
      copy[i] = copyTree(x[i]);
    }
    return copy;
  } else if (x === Object(x) && typeof x !== "function") {
    var copy = {};
    for (var k in x) {
      copy[k] = copyTree(x[k]);
    }
    return copy;
  } else {
    return x;
  }
}
res.arr1 = arr.filter(f).map(copyTree);
res.arr2 = arr.filter(f).map(copyTree);

请注意,嵌套数组会出现同样的问题,因此上面的数组测试。