前言#
最近被流放到处理缺陷去了,所以时间又多了起来~
然后就遇到了标题中的这个问题
我们可以用babel来让代码变得更“直接”
前置#
首先我们需要了解下?.可选链运算符
?.可选链运算符#
具体可见:Optional chaining (?.) - JavaScript | MDN (mozilla.org)
用法很简单,就是在字段的前面加上?.,这样整体就不会报错了

可以看到第二个因为没有?.,引起了报错。
那么这样在很多场景中就会非常方便,我们不再需要去aaa && aaa.b && aaa.b.c这样去判断。
然后我们来看下这个运算符的兼容性:

看起来全支持呢~ 实际上只是现代浏览器,我们的老朋友:《IE》完全不支持。
然后我们再来看下babel相关的polyfill。
polyfill#
之前我有写过一篇入门的文章,可以去了解下 babel入门学习 - 知乎 (zhihu.com)
实际上你可能会想,既然现代浏览器都支持,并且我用的框架自身就只支持现代浏览器,那我完全没必要去处理。
实际上如果你的项目中引入了babel并且没做特殊配置,那么这个方法就会被polyfill掉, 因为?.是ES6引入的运算符,比如如下配置
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "entry",
corejs: "3.25.5",
},
],
["@babel/preset-react"]
],
};就不讲这里面这些项是干啥的了。
我们来搞个例子,配置就是上面那块
const { transform } = require('@babel/core');
const res = transform(`if (a?.b?.c) {}`, {
// ast: true
})
console.log(res);然后运行它,来看下结果

可以看到被polyfill成es5可以理解的代码块,基本和我们以前a && a.b && a.b.c这种写法差不多。
ok,那么我们的前置了解就到这里,接下来进入主题。
bug#
我们直接来看下代码
const { transform } = require('@babel/core');
const str = `
function test (value) {
if (value?.indexOf("aa") == -1) {
return true
}
return false
}
`
const res = transform(str, {
// ast: true
})
console.log(res.code);
我们的问题代码是value?.indexOf("aa") == -1, 这一行代码咋一看是正常的,没啥问题。
然后我们用babel转换成更直接的方式

(value === null || value === void 0 ? void 0 : value.indexOf("aa")) == -1咋一看也没啥问题呀?
但是别忘了,这是在一个if语句里。如果value为undefined,那么这个时候indexOf就不会被执行,而是void 0。 那么这个if语句就是false。
但这里的预期是''.indexOf("aa") == -1也是true。那么这个逻辑就有问题了。
这个if语句的判断逻辑因为这个?.而发生了变化。
处理方案#
处理方案也简单,就是想办法确保这个语句一定会执行,既然value是undefined,那我们加个默认值即可。
(value || '')?.indexOf("aa") == -1 然后我们再来看下转换出来的代码

这样就必定会执行了。
总结#
挺有意思的一个bug。
谨慎在if语句中使用?.[method](这里的method指的是一些用于判断相关的方法),除非忍不住除非你确定这里不会有undefined等。
编辑于 2023-11-13 19:25・IP 属地广东
