我注意到在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
保持一开始就一样。
谢谢。
您的代码在这里:
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}];
这就是我们记忆中的内容(忽略了一些无关紧要的细节);
+------------+ | 变量“ a” | +------------+ +----------- | Ref11542 | ---- >> 数组| +------------+ +-------------+ | 0:Ref88464 | ---- >> 对象 +------------+ +----------- | 答案:null | +------------+
a
引用具有0
属性的数组对象,引用具有该answer
属性的对象。我使用“Ref11542”和“Ref88494”来表示的对象引用a
和a[0]
包含,但当然我们从来没有真正看到这些参考值; 它们是JavaScript引擎专用的。
然后我们这样做:
var b = a.filter(function() { return true; }); // Just a copy, but using `filter` for emphasis
现在我们有:
+------------+ | 变量“ a” | +------------+ +----------- | Ref11542 | ---- >> 数组| +------------+ +----------- | 0:Ref88464 |-+ +----------- | | +------------+ +------------+ +-> | 对象 | 变量“ b” | | +------------+ +------------+ | | 答案:null | | Ref66854 | ---- >> 数组| | +------------+ +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------年年级 | 0:Ref88464 |-+ +------------+
请注意,两个数组都包含相同的对象引用(此处显示为“ Ref88464”);他们指向同一个对象。
现在我们这样做:
a[0].answer = 42;
所要做的就是改变对象的状态。它有没有影响a
或b
或阵列它们指的是:
+------------+ | 变量“ a” | +------------+ +----------- | Ref11542 | ---- >> 数组| +------------+ +----------- | 0:Ref88464 |-+ +----------- | | +------------+ +------------+ +-> | 对象 | 变量“ b” | | +------------+ +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------年年级 | 答案:42 | | Ref66854 | ---- >> 数组| | +------------+ +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------年年级 ^ | 0:Ref88464 | − + + −−−−−−−只有变化在这里 +------------+
很自然
console.log(b[0].answer);
...输出42。
在评论中,您要求:
但是,如何设置过滤对象而不是主要对象的状态?
请记住,两个数组中的对象相同。您尚未复制对象,只是创建了一个仅包含其中一些对象的新数组。
如果希望能够更改那些对象的属性而又不影响第一个数组中的对象,则需要制作这些对象的副本。
如果对象仅包含简单的原始值,那很容易;否则,这很简单。一般情况很难。:-)
但是,就您的情况而言,由于您的对象仅具有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);
或者,您可能只想对数组进行一次遍历:
var filtered = [];
array.forEach(function(x){
if (x.name !== "mike") {
filtered.push({name: x.name + "[NEW]"});
}
});
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句