125

字符串拼接引发的BUG | Fundebug博客

 6 years ago
source link: https://blog.fundebug.com/2017/11/20/bug-fix-concatenated-string-trun-into-numbers/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

字符串拼接引发的BUG

译者按: bug 虽小,却是个磨人的小妖精!

本文采用意译,版权归原作者所有

这是一篇很简短的博客,记录了我今天早上花了一个小时才解掉的一个 bug。

在已有的网站页面,我们已经有一段 JavaScript 代码用于构建字符串并把它插入到 DOM 中,如下所示:

function GetTemplate(url, html) {
// 省掉部分细节代码
// ...
var template =
'<div class="something"><a href="' +
url +
'" target="_blank"><strong>Details: </strong><span>' +
html +
"</span></a></div>";
return template;
}

请忽略这段代码的粗糙。接下来,我们的需求很简单:如果summary存在,那么在<strong>标签前面添加一个额外的<span>标签将该值显示出来。是不是很简单?我们来试一试。

我快速实现了如下代码:

function GetTemplate(url, html, summary) {
// other details removed
var template =
'<div class="something"><a href="' + url + '" target="_blank">';

if (summary) {
template += '<span class="summary">' + summary + "</span>";
}

template +=
+"<strong>Details: </strong><span>" + html + "</span></a></div>";

return template;
}

看上去一切 OK,没有问题。F5刷新页面,看起来不大对:

first_try_fail.png

你知道哪里出问题了吗?

由上面的代码生成的 HTML 长这样:

<div class="something"><a href="https://thewebsite.com" target="blank">
<span class="summary">The summary</span>NaNThis is the inner message</span></a>
</div>

发现问题了吗?如果没发现,我们接着往下看。

你的线上代码真的没有 BUG 吗?欢迎免费使用Fundebug!我们可以帮助您第一时间发现 BUG!

字符串拼接 vs 加法

仔细查看生成的 HTML 代码,你会发现NaN出现在</span>标记的后面,然而<strong>标签不见了。NaN是一个很好的线索,表明这里有类型转换发生,并且是转换为 Number 类型,但是我当时一直没有找到发生转换的原因!

接下来,我们先温习一下 JavaScript 基础知识。在 JavaScript 中,根据+左右两边变量的类型的不同,+符号可以用于数字相加或则字符串拼接。

console.log("value:" + 3); // 'value:3'
console.log(3 + 1); // 4
console.log("value:" + 3 + "+" + 1); // 'value:3+1'
console.log("value:" + 3 + 1); // 'value:31'
console.log("value:" + (3 + 1)); // 'value:4'
console.log(3 + " is the value"); // '3 is the value'

在上面的这些例子中,如果+的任何一边是字符串,那么另一边一定会转换为字符串。否则,将看做是数字相加。

因此,NaN预示着一定是字符串被误用为数字了。但我并没有使用parseInt()函数做类型转换,所以逻辑上说不通啊!

最终,我逐步缩小出错区域,发现是如下代码出错:

template += +"<strong>Details: </strong><span>" + html + "</span></a></div>";

如果你还是没看出来,那么我们换个写法:

template += +"<strong>Details: </strong><span>" + html + "</span></a></div>";

我用了string += +string这样的写法,也就是说:由于写代码的时候拷贝黏贴,不小心整了一个多余的+号?所以,相当于使用了一元运算+。根据一元运算符(+)的官方解释:+c会显示地将c转换为 Number 类型。

这就是我的代码出现 bug 的根源:一元运算符+号尝试将<strong>Details: </strong><span>转换为数字,但是失败了返回NaN。然后NaN又转换为字符串拼接起来。当我把这个额外的+删掉后,代码就正确运行了。

另外值得一提的是,我使用了gulp-uglify来压缩我的 JavaScript 代码。在构建过程中,一元运算(+'<strong>Details: </strong><span>')已经在压缩后的代码中存储为NaN了。Gulp已经识别出代码错误。

从这一次 Debug 的经历吸取了一个教训:不要马马虎虎的拷贝黏贴代码!而且我立即想到如果有一个小的gulp插件可以识别并提醒压缩代码中有莫名其妙的NaN的话,也可以适当避免问题。

> parseInt('<strong>Details: </strong><span>')
NaN
> +'<strong>Details: </strong><span>'
NaN

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了70亿+错误事件,付费客户有阳光保险、达令家、核桃编程、荔枝FM、微脉等众多品牌企业。欢迎大家免费试用

您的用户遇到BUG了吗?

体验Demo 免费使用

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK