我注意到node.js上的数组过滤器中有一些奇怪的行为。 有一个简单的数组和一个循环:
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,这是我在控制台中得到的:
[ { 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
为什么会这样?我需要array
保持与开头相同。
感谢。
答案 0 :(得分:7)
您的代码在这里:
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
}
...无法更改 数组。它改变了两个数组引用的对象的状态。
更简单的例子:
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]
也指的是到。
让我们抛出一些 ASCII-art Unicode -art:
这一行之后:
var a = [{answer:null}];
这就是我们在记忆中所拥有的(忽略一些不相关的细节);
+−−−−−−−−−−−−−−+ | variable "a" | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | Ref11542 |−−−−>| array | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | 0: Ref88464 |−−−−>| object | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−+ | answer: null | +−−−−−−−−−−−−−−+
a
是指一个数组对象,它具有0
属性,该属性引用具有answer
属性的对象。我正在使用&#34; Ref11542&#34;和&#34; Ref88494&#34;表示a
和a[0]
包含的对象引用,但当然我们实际上从未看到这些引用的值;他们是JavaScript引擎专用的。
然后我们这样做:
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 |−−+ +−−−−−−−−−−−−−−+
请注意,两个数组都包含相同的对象引用(此处显示为&#34; Ref88464&#34;);他们指向相同的对象。
现在我们这样做:
a[0].answer = 42;
所有这一切都是改变对象的状态;它对a
或b
或它们引用的数组没有影响:
+−−−−−−−−−−−−−−+ | 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。
在评论中你曾问过:
但是,如何设置过滤对象的状态而不是主要对象?
请记住,对象在两个数组中都是相同的。你还没有复制这些对象,你刚刚创建了一个只包含其中一些的新数组。
如果您希望能够更改这些对象&#39;在不影响第一个数组中对象的属性的情况下,您需要创建对象的副本。
如果对象只包含简单的原始值,那很容易;一般情况很难。 : - )
但是,在你的情况下,因为你的objets只有name
和planet
属性,接下来要做的就是删除planet
属性并更改名称,我们可以随时随地轻松创造物体;见评论:
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);
&#13;
或者,您可能只希望通过数组进行一次传递:
var filtered = [];
array.forEach(function(x){
if (x.name !== "mike") {
filtered.push({name: x.name + "[NEW]"});
}
});