字元串拼接引發的BUG
- 2019 年 12 月 31 日
- 筆記
譯者按: 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版權聲明
轉載時請註明作者 Fundebug以及本文地址: https://blog.fundebug.com/2017/11/20/bug-fix-concatenated-string-trun-into-numbers/

