这个基本代码片段出了什么问题

时间:2018-11-26 13:48:52

标签: javascript typescript sorting memory

当我发现我的代码出了点问题时,我正在一个个人项目上。经过几分钟的调试,我能够说出问题所在和解决方法。但是实际上我还没有解决我原来的问题。

看看这个:

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的基本概念,还是我犯了愚蠢的错误,使我的代码做了奇怪的事情?

1 个答案:

答案 0 :(得分:1)

zoobis = zoo;

仅使zoobiszoo变量都指向相同对象。然后,一行

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