js数组对象push重复

this.form = res.data.data.records[0];
this.form.inventoryWorkSubunitList.forEach((el) => {
    var data = {};
    if (el.assetSn == qr) {
        el.physicalInventory = 1;
        alert(1);
        return;
    } else {
        alert(2);
        getAssetBook({ assetSn: qr }).then((res1) => {
            if (res1.data.code == 200) {
                data.assetName = res1.data.data.assetName;
                data.assetSn = res1.data.data.assetSn;
                data.model = res1.data.data.model;
                data.location = res1.data.data.location;
                data.unit = res1.data.data.unit;
                data.amount = 0;
                data.assetType = res1.data.data.assetType;
                data.assetBrand = res1.data.data.assetBrand;
                data.whomBelongs = res1.data.data.whomBelongs;
                data.purchaseAmount = res1.data.data.purchaseAmount;
                data.physicalInventory = 1;
                this.form.inventoryWorkSubunitList.push(data);
            }
        });
    }
});

本来this.form.inventoryWorkSubunitList就有值,else情况时,这样一循环就会重复push,怎么解决

阅读 5.4k
2 个回答

假设assetName是唯一字段,push前加个判断即可

if(this.form.inventoryWorkSubunitList.findIndex(item=>item.assetName == data.assetName) == -1){
   this.form.inventoryWorkSubunitList.push(data);
}

从代码分析,大概是想遍历 inventoryWorkSubunitList,逐个判断其元素的 assetSn,如果符合(或达不到)某个条件,就去远程获取相关信息,更新当前元素对象(是替换元素,而不是加入列表)。

更新列表元素有两个办法,一个是使用 .map(),把整个列表都更新。这种办法的问题是,如果没有一个元素更新,整个列表对象也会更新,有可能会引起重绘(比如 Vue 中)。另一种办法是直接更新元素的各属性,也就是重新给其属性赋值,这种方法要求元素本身是个对象(不是 null),可改变。如果这两种方法都不可行,还可以使用原始的 for 循环来处理。因为过程中涉及异步过程,目前最合适的可能还是直接改变元素属性。

下面给个关键过程示例:

this.form.inventoryWorkSubunitList.forEach((el) => {
    if (el.assetSn === qr) {
        el.physicalInventory = 1;
        return;
    } else {
        getAssetBook({ assetSn: qr }).then((res1) => {
            if (res1.data.code == 200) {
                Object.assign(
                    el,
                    res1.data.data,
                    {
                        amount: 0,
                        physicalInventory : 1,
                    }
                );
            }
        });
    }
});

else 分支里经过一个异步获取数据的过程,然后如果返回的数据有效,就用 Object.assign() 改变 el 的属性(对象还是那个对象,只是属性变了)。这里使用 Object.assign() 可以简化赋值代码,但是也要注意 res1.data.data 中的所有属性都会赋值过去,如果这里面的属性值过多,或者有不想改变的值,可能会与预期不同,谨慎使用

此外,也可以等异步过程完全结束来一次性改变 inventoryWorkSubunitList。这里需要先处理 getAssetBook 的返回,毕竟只有有效返回才会使用。

const promises = this.form.inventoryWorkSubunitList
    .map(el => {
        if (el.assetSn === qr) { return el; }
        return (async () => {
            try {
                const res = await getAssetBook({ assetSn: qr });
                if (res.data.code === 200) {
                    return {
                        ...res.data.data,
                        amount: 0,
                        physicalInventory: 1,
                    };
                } else {
                    // 如果远程获取无效,使用原对象
                    return el;
                }
            } catch (err) {
                // 这是进入异步的 reject 处理过程
                return el;
            }
        })();
    });

Promise.all(promises).then(data => this.form.inventoryWorkSubunitList = data);

说了这么多,都是在讨论方法。感觉跟实际业务有些出入,因为 getAssetBook({ assetSn: qr }) 这里的 qr 赋值不在处理的这段代码内,也就意味着它在这段代码中是个常量,理论上来说,不管多少次 getAssetBook({ assetSn: qr }) 都应该得到同样的结果,那么最终处理出来的数据,应该也是重复的……

推荐问题