admin管理员组文章数量:1278978
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
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.
Thanks.
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
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.
Thanks.
Share Improve this question asked Aug 7, 2016 at 14:41 NedNed 3713 silver badges17 bronze badges 2-
It is a mon JS paradigm, google
mutable Js objects
– Shintu Joseph Commented Aug 7, 2016 at 14:44 - looks like you are ready for immutable.js if you don't want to mutate the objects that are referenced inside both arrays – Aprillion Commented Aug 7, 2016 at 14:45
1 Answer
Reset to default 11Your code here:
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.
Simpler example:
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
This line:
a[0].answer = 42;
doesn't change a
or b
, it changes the state of what a[0]
refers to, which b[0]
also refers to.
Let's throw some ASCII-art Unicode-art at it:
After this line:
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
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.
Then we do this:
var b = a.filter(function() { return true; }); // Just a copy, but using `filter` for emphasis
Now we have:
+−−−−−−−−−−−−−−+ | variable "a" | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | Ref11542 |−−−−>| array | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | 0: Ref88464 |−−+ +−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ +−>| object | | variable "b" | | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | | answer: null | | Ref66854 |−−−−>| array | | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | | 0: Ref88464 |−−+ +−−−−−−−−−−−−−−+
Note that both arrays contain the same object reference (shown here as "Ref88464"); they point to the same object.
Now we do this:
a[0].answer = 42;
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 +−−−−−−−−−−−−−−+
So naturally
console.log(b[0].answer);
...outputs 42.
In a ment you've asked:
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. :-)
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 ments:
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]"});
}
});
本文标签: javascriptArray filter changes the main arrayStack Overflow
版权声明:本文标题:javascript - Array filter changes the main array - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741280288a2369969.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论