字符串拼接引發的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刷新頁面,看起來不大對:


你知道哪里出問題了嗎?

由上面的代碼生成的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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM