数组过滤器更改主数组 [英] Array filter changes the main array

查看:66
本文介绍了数组过滤器更改主数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到node.js上的数组过滤器中有一些奇怪的行为。
有一个简单的数组和一个循环:

I've noticed some strange behavior in the array filters on node.js. There is a simple array and a loop:

var array = [
{
    name:"bob",
    planet:"earth"
},
{
    name:"mike",
    planet:"mars"
},
{
    name:"vlad",
    planet:"jupiter"
}];

var filtered = array.filter(function(x){
    return x.name !== "mike";
});

console.log(array); //lets print how normal array looks like
console.log("---");
console.log(filtered); //lets print how filtered one looks like

for(var i = 0; i < filtered.length; i++)
{
    delete filtered[i].planet; //remove planet
    filtered[i].name = filtered[i].name + "[NEW]"; //add NEW to the name
}

console.log("After replacement:");
console.log(array);//lets print how normal array looks like now
console.log("-----------");
console.log(filtered);//lets print how filtered array looks like now

理论上, array 数组不应该被更改,因为我没有以任何方式操纵它。 Hovewer,这是我在控制台得到的:

In theory, array array should not be changed, since I did not manipulate it in any way. Hovewer, this is what I get in console:

[ { name: 'bob', planet: 'earth' },
  { name: 'mike', planet: 'mars' },
  { name: 'vlad', planet: 'jupiter' } ] //this array is normal
---
[ { name: 'bob', planet: 'earth' },
  { name: 'vlad', planet: 'jupiter' } ] //this is good behavior, since I don't need "mike"

After replacement:

[ { name: 'bob[NEW]' },
  { name: 'mike', planet: 'mars' },
  { name: 'vlad[NEW]' } ] //this should not be changed in any way
-----------
[ { name: 'bob[NEW]' }, { name: 'vlad[NEW]' } ] //this is correct

为什么会这样?我需要数组保持与开头相同。

Why does this happen? I need array to stay the same as in the beginning.

谢谢。

推荐答案

您的代码在这里:

for(var i = 0; i < filtered.length; i++)
{
    delete filtered[i].planet; //remove planet
    filtered[i].name = filtered[i].name + "[NEW]"; //add NEW to the name
}

...未更改 阵列。它正在改变两个数组引用的对象的状态。

...isn't changing either array. It's changing the state of the objects that both arrays refer to.

更简单的例子:

var a = [{answer:null}];
var b = a.filter(function() { return true; }); // Just a copy, but using `filter` for emphasis
a[0].answer = 42;
console.log(b[0].answer); // 42

此行:

a[0].answer = 42;

不会改变 a b ,它改变了 a [0] 所指的状态,其中 b [0] 指的是。

doesn't change a or b, it changes the state of what a[0] refers to, which b[0] also refers to.

让我们抛出一些 ASCII-art Unicode -art at it:

Let's throw some ASCII-art Unicode-art at it:

此行之后:

var a = [{answer:null}];

这就是我们内存中的内容(忽略一些不相关的细节);

this is what we have in memory (ignoring some irrelevant details);


+−−−−−−−−−−−−−−+
| variable "a" |
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+
| Ref11542     |−−−−>|    array     |
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+
                     | 0: Ref88464  |−−−−>|    object    |
                     +−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+
                                          | answer: null |
                                          +−−−−−−−−−−−−−−+

a 指的是一个数组对象,它有一个 0 属性,它引用带有回答的对象财产。我使用Ref11542和Ref88494来表示 a a [0] 包含的对象引用,但我们当然从未真正看到这些参考文献的价值;它们是JavaScript引擎专用的。

a refers to an array object, which has a 0 property, which refers to the object with the answer property. I'm using "Ref11542" and "Ref88494" to represent the object references that a and a[0] contain, but of course we never actually see the value of those references; they're private to the JavaScript engine.

然后我们这样做:

var b = a.filter(function() { return true; }); // Just a copy, but using `filter` for emphasis

现在我们有:


+−−−−−−−−−−−−−−+
| variable "a" |
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+
| Ref11542     |−−−−>|    array     |
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+   
                     | 0: Ref88464  |−−+
                     +−−−−−−−−−−−−−−+  |
                                       |
                                       |  +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+                       +−>|    object    |
| variable "b" |                       |  +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+  |  | answer: null |
| Ref66854     |−−−−>|    array     |  |  +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+  |
                     | 0: Ref88464  |−−+
                     +−−−−−−−−−−−−−−+

注意两个数组都包含相同的对象引用(此处显示为Ref88464);他们指向相同的对象。

Note that both arrays contain the same object reference (shown here as "Ref88464"); they point to the same object.

现在我们这样做:

a[0].answer = 42;

所有这一切都是改变对象的状态;它对 a b 或它们引用的数组没有影响:

All that does is change the state of the object; it has no effect on a or b or the arrays they refer to:


+−−−−−−−−−−−−−−+
| variable "a" |
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+
| Ref11542     |−−−−>|    array     |
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+   
                     | 0: Ref88464  |−−+
                     +−−−−−−−−−−−−−−+  |
                                       |
                                       |  +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+                       +−>|    object    |
| variable "b" |                       |  +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+  |  | answer: 42   |
| Ref66854     |−−−−>|    array     |  |  +−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−+  |             ^
                     | 0: Ref88464  |−−+             +−−−−−−− only change is here
                     +−−−−−−−−−−−−−−+

很自然地

console.log(b[0].answer);

...输出42。

在评论中你问过:


但是我如何设置状态过滤的对象而不是主要对象?

But then how do I set the state of filtered object and not the main one?

请记住,两个数组中的对象是相同的。你还没有复制过这些对象,你刚刚创建了一个只包含其中一些的新数组。

Remember, the objects are the same in both arrays. You haven't copied the objects, you've just created a new array that only has some of them in it.

如果你想能够改变那些对象'属性不影响第一个数组中的对象,你需要对对象进行拷贝

If you want to be able to change those objects' properties without affecting the objects in the first array, you need to make copies of the objects.

如果对象只包含简单的原始值, 这很简单;一般情况很难。 : - )

If the objects contain only simple primitive values, that's easy; the general case is quite hard. :-)

在你的情况下,因为你的objets只有 name planet 属性,接下来要做的就是删除 planet 属性并更改名称,我们可以轻松创建对象;看评论:

In your case, though, since your objets just have name and planet properties, and the very next thing you do is remove the planet property and change the name, we can easily create objects as we go; see comments:

var array = [
{
    name:"bob",
    planet:"earth"
},
{
    name:"mike",
    planet:"mars"
},
{
    name:"vlad",
    planet:"jupiter"
}];

var filtered = array.filter(function(x){
    return x.name !== "mike";
}).map(function(x) {
    // Create a *new* object, setting its `name` to the `name`
    // of the original object plus [NEW], and ignoring its
    // `planet` property entirely
    return {name: x.name + "[NEW]"};
});

console.log(array);
console.log("---");
console.log(filtered);

或者,您可能只需要通过一次数组:

Alternately, you might want to make just one pass through the array:

var filtered = [];
array.forEach(function(x){
    if (x.name !== "mike") {
        filtered.push({name: x.name + "[NEW]"});
    }
});

这篇关于数组过滤器更改主数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆