当我发现我的代码出了点问题时,我正在一个个人项目上。经过几分钟的调试,我能够说出问题所在和解决方法。但是实际上我还没有解决我原来的问题。
看看这个:
interface Animals {
id: number;
name: string;
color: string;
}
interface Zoo {
name: string;
animals: Animals[];
}
function main() {
let zoo: Zoo = {
name : "Valley of monkeys",
animals : [
{
id : 1,
name: "Foufou",
color: "brown"
},
{
id: 2,
name: "Toutou",
color: "brown"
},
{
id: 3,
name: "Moumou",
color: "blue"
}
]
};
let zoobis: Zoo;
zoobis = zoo;
console.log(zoobis);
console.log(zoo);
zoobis.animals = zoo.animals.filter((animal) => animal.color === "brown");
console.log("============");
console.log(zoobis);
console.log(zoo);
}
main();
Link to Typescript Playground to test it:
如您所见,存在两个主要问题:
第一个是两个数组都被修改了!即使在javascript官方文档中,它也指定“ filter()不会使调用它的数组发生变化。”
第二个是在调用实际上是很奇怪的filter之前修改了两个数组。
解决方法基本上是将“ zoobis”转换为Animal [],而不是获取整个Zoo对象。似乎通常以这种方式工作。
我是否误解了javascript的基本概念,还是我犯了愚蠢的错误,使我的代码做了奇怪的事情?
答案 0 :(得分:1)
行
zoobis = zoo;
仅使zoobis
和zoo
变量都指向相同对象。然后,一行
zoobis.animals = zoo.animals.filter((animal) => animal.color === "brown");
修改两个变量都指向的一个对象的状态,用新的过滤数组替换其animals
属性。
自然地,无论您是通过zoobis
还是通过zoo
来查看同一对象状态,因为这两个变量都指向同一对象。
一些ASCII艺术:
一旦创建了zoo
对象,内存中就会隐约有这样的东西:
+−−−−−−−−−−−−−−−−+ +−>| (object) | +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ zoo:[Ref71234]−−−−−−>| (object) | | | id: 1 | +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | name: "Foufou" | | name: "Valley of monkeys" | +−−−−−−−−−−−−−−−+ | | color: "brown" | | animals: [Ref55412] |−−>| (array) | | +−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | | 0: [Ref45132] |−+ +−−−−−−−−−−−−−−−−+ | 1: [Ref45174] |−−−−−−−−−−−−−−−−−−−−−−−>| (object) | | 2: [Ref45228] |−+ +−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ | id: 2 | +−>| (object) | | name: "Toutou" | +−−−−−−−−−−−−−−−−+ | color: "brown" | | id: 3 | +−−−−−−−−−−−−−−−−+ | name: "Moumou" | | color: "blue" | +−−−−−−−−−−−−−−−−+
请注意,zoo
包含对该对象的引用(在概念上显示为[Ref71234],但您实际上从未在代码中看到对象引用的值)。
然后在zoobis = zoo;
之后,您将拥有:
zoo:[Ref71234]−−+ | +−−−−−−−−−−−−−−−−+ | +−>| (object) | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ +−−−>| (object) | | | id: 1 | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | name: "Foufou" | | | name: "Valley of monkeys" | +−−−−−−−−−−−−−−−+ | | color: "brown" | | | animals: [Ref55412] |−−>| (array) | | +−−−−−−−−−−−−−−−−+ zoo:[Ref71234]−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | | 0: [Ref45132] |−+ +−−−−−−−−−−−−−−−−+ | 1: [Ref45174] |−−−−−−−−−−−−−−−−−−−−−−−>| (object) | | 2: [Ref45228] |−+ +−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ | id: 2 | +−>| (object) | | name: "Toutou" | +−−−−−−−−−−−−−−−−+ | color: "brown" | | id: 3 | +−−−−−−−−−−−−−−−−+ | name: "Moumou" | | color: "blue" | +−−−−−−−−−−−−−−−−+
请注意如何将zoo
([Ref71234])的值复制到zoobis
中,但是该值只是对 one 对象的引用。
然后在[过滤器]之后:
zoo:[Ref71234]−−+ | +−−−−−−−−−−−−−−−−+ | +−>| (object) | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ +−−−>| (object) | | | id: 1 | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | name: "Foufou" | | | name: "Valley of monkeys" | +−−−−−−−−−−−−−−−+ | | color: "brown" | | | animals: [Ref65241] |−−>| (array) | | +−−−−−−−−−−−−−−−−+ zoo:[Ref71234]−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | | 0: [Ref45132] |−+ +−−−−−−−−−−−−−−−−+ | 1: [Ref45174] |−−−−−−−−−−−−−−−−−−−−−−−>| (object) | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−+ | id: 2 | | name: "Toutou" | | color: "brown" | +−−−−−−−−−−−−−−−−+
请注意,由于创建并存储了新数组,因此如何将旧animals
值([Ref55412])替换为新值([Ref65241])。
如果要复制 zoo
,则可以使用Object.assign
或属性传播(ES2018 +):
zoobis = Object.assign({}, zoo);
// or
zoobis = {...zoo};
这将产生浅的副本(例如,两个对象的animals
属性都指向相同数组)。浅表副本足以满足您的显示要求(但如果zoo
上有其他属性引用对象,则可能会出现问题)。
如果要制作深副本,请参见this question's answers。