字元串拼接引發的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/

Tags: