Published on

记一次有趣的 bug

Authors

Question

我想任何一个前端开发者都会不假思索地说出 [...new Set(arr)] 不就是对数组 arr 进行简单的去重嘛? 这太常用了.

是的没错, 这也就是我苦恼的地方, 且听我娓娓道来.

背景

某个项目使用的是 vue3 技术栈, 但是公司自研的组件库是基于 react 的, 因此在领导的要求下, 我们对项目进行了重构.

组长找了个开源的 react 项目模板, 于是我们开启了风风火火的重构之路. 问题也就此埋下.

发现问题

在写一个 echarts 图表, 但是没有按照预期把图渲染出来, 检查下代码, 应该没什么问题, 按理说应该和在 vue 中的表现一样呀? 于是我 debug 了一下, 好家伙 😂 在一个处理数据的公共方法中让我发现了端倪: [...new Set(arr)] 返回的结果打破了我的认知 --- 比如 [...new Set(1,1,2)], 按照常规的理解, 应该f返回 [1, 2], 但在这个项目里就不一样了, 它返回的是 [Set(2)]...干了这么多年, 还真就第一次见~

排查

首先我陷入了自我怀疑😂, 难道是我记错了? 于是我赶紧创建了个 js, 然后 node 跑了一下, 没毛病呀, 得到的是期望的 [1, 2].

问题出在哪里了呢? 得益于之前系统地学习过 babel 相关知识,我猜测问题应该是出现在了编译阶段, 并且大概率和 babel 的配置有关, 于是我看了下 .babelrc 文件, 有这么一个配置引起了我的注意:

.babelrc.js
module.exports = {
    presets: [
        [
            '@babel/preset-env',
            {
                useBuiltIns: 'usage',
                corejs: 3,
                loose: true // ❕ Here
            }
        ],
        // ...
    ]
    // ...
}

loose: true, 这是个啥呀? 以前好像从来没有用过, 先去官网搜了一下, 有点不明所以, 可能是因为现在的文档比较新了, 对这个描述比较简略.

于是我又打开 google 搜索关键字: "new set, babel loose", 还真让我搜了一篇比较详细的文章: Babel 6: loose mode. 其中, 对于开启 loose 的缺点是这么描述的:

You risk getting problems later on, when you switch from transpiled ES6 to native ES6. That is rarely a risk worth taking.

简言之就是在把编译好的 es6 代码转为原生 es6 代码时有一定风险产生不可预知的问题.

解决

知道了症结在哪里, 那么就解决就很容易了. 把 loose 改为 false 后, [...new Set(arr)] 的表现就回归正常了.

But, 以防还有什么其他的不可预知的问题, 我还是比较谨慎地把 [...new Set(arr)] 的语法改为了 Array.from(new Set(arr)), 也能解决问题, 使得对项目整体的影响最小, 完美解决.