数组过滤器没有 return 预期结果

Array filter does not return expected result

我正在尝试过滤 typescript 中的数组我得到了预期的结果,但原始集合被更改了。

private filter(){
            this.data = this.originalData.slice().filter((client: Client) => {
                // Filter list of orders first
                let filteredListOfOrders = client.ListOfOrders.slice().filter((ordersItem: any) => {
                    const searchStr = JSON.stringify(ordersItem).toLowerCase();
                    return searchStr.indexOf(this.filterValue.toLowerCase()) !== -1;
                });

                // Assign filtered list of orders to existing client item 
                client.ListOfOrders = filteredListOfOrders;

                const searchStr = JSON.stringify(client).toLowerCase();
                return searchStr.indexOf(this.filterValue.toLowerCase()) !== -1;
            });
}

export class Client {
   id: number;
   name: string;
   address: string;
   orders: Array<Order>;
}

export class Order {
    id: number;
    dateOfOrder: Date;
    address: string;
}

当我键入地址时,我还想搜索除客户之外的订单项目,return 仅搜索具有过滤地址的客户和具有过滤地址的订单。上面的部分工作但它给我带来了一个问题,因为 this.originalData 被修改并且只设置了与过滤器匹配的订单。 this.originalData 应该保持完整。

有谁知道为什么?认为 slice return 是浅拷贝

嗯,这不适合发表评论,所以我将其扩展为一个答案:

您没有以有意义的方式使用术语 "shallow"。价值观不浅也不深。 副本有浅有深。

对象的副本(数组只是一个对象)是一个新对象,其属性包含对非常相同的对象的引用 作为原始对象的属性。如果您修改浅拷贝的其中一个属性的内容,您将在原始对象的类似 属性 中看到该修改,因为这两个属性都指向 非常相同的对象

如果您希望能够在不触及原始内容的情况下修改副本的内容,则需要执行 深度 复制,在其中递归遍历所有属性每个对象及其所有属性,并制作实际副本。

并不总是需要完整的深拷贝;通常你只关心修改你的数据结构的一部分,你可以将不变的部分保留为浅拷贝。


针对您的具体情况:您正在修改 Client,方法是将其 orders 数组替换为包含原始内容的某些子集的新数组,并且您没有更改这些内容。所以你真的只需要一个 Client 对象的浅拷贝。你根本不需要 slice() 因为你不关心复制数组(并且 filter() 总是 returns 一个新数组)。你想做这样的事情:

private filter(){
            this.data = this.originalData.filter((client: Client) => {

                // Filter list of orders first
                let filteredListOfOrders = client.ListOfOrders.filter((ordersItem: any) => {
                    const searchStr = JSON.stringify(ordersItem).toLowerCase();
                    return searchStr.indexOf(this.filterValue.toLowerCase()) !== -1;
                });

                const clientCopy = Object.assign({}, client);
                // Assign filtered list of orders to copied client item 
                clientCopy.ListOfOrders = filteredListOfOrders;

                const searchStr = JSON.stringify(clientCopy).toLowerCase();
                return searchStr.indexOf(this.filterValue.toLowerCase()) !== -1;
            });
}

请注意,我这样说 "something like",因为您的代码无法为我编译(complete and verifiable 示例总是有帮助的)。所以你必须调整以上内容以满足你的需要。

希望对您有所帮助;祝你好运!