要在 JavaScript 把 snake_case 轉成 camelCase,先以底線分割字串、把每個 token 轉成小寫,然後讓第一個 token 保持小寫,並將後續每個 token 的第一個字母大寫,因此 user_first_name 一次就能變成 userFirstName。困難的不是大小寫規則,而是分詞步驟。真實識別名稱會混入 XMLHttpRequest 這類縮寫、v2Endpoint 這類數字、標點,以及不一致的大小寫(snake_case、kebab-case、PascalCase、ALL CAPS),而在每個大寫字母前插入底線的天真 regex,會把 XMLHttpRequest 變成 x_m_l_http_request,這不是你要的。Camel Case 轉 Snake Case 轉換器 在同一處處理該分詞:切開小寫到大寫的轉換、把縮寫從緊接其後的大寫單詞切開,並把任何非字母且非數字的連續字元當成 token 邊界。接著它從單一確定性 token 清單一次組出六種命名風格,因此同一輸入可為變數、類別、env 檔或顯示標籤重新格式化,不必再貼一次或再分詞一次。

how to convert snake case to camel case in javascript
如何在 javascript 把 snake case 轉成 camel case

為什麼 JavaScript 專案一開始就會碰到 snake_case

JavaScript 本身偏好用 camelCase 當區域變數與函式名稱,但進入 JavaScript 程式庫的識別名稱不一定這樣寫。Python、Ruby 與 Go 的後端常以 snake_case 暴露 JSON 欄位。SQL 資料庫通常用 snake_case 存欄位名稱。環境變數慣例是 UPPER_SNAKE_CASE,許多 REST API 也為了跨語言一致性用 snake_case 文件化 payload。當前端、Node 服務或 TypeScript 層要消費這些值時,必須先轉換它們,才能與程式庫其餘部分一致。移植函式庫、在 hydration 步驟裡正規化資料、從 schema 為 ORM 產生屬性名稱,或把從 CMS 匯入的 slug 改成元件能讀的屬性時,也會出現同一項工作。

這通常就是人們會寫個快速輔助函式的部分:拿像 user_first_name 這樣的字串,用 _ 分割,把每一段轉小寫,再把除了第一段以外每一段的第一個字母大寫後串起來。輔助函式對乾淨輸入有效,一旦識別名稱帶有縮寫、連續數字,或從設定檔帶進來的標點,就會垮掉。那時候單行 regex 不夠用,你會想要一個已經知道小寫到大寫轉換、縮寫邊界與非字母分隔符規則的分詞器。

snake_case 轉 camelCase 的規則,直說

轉換規則本身很短。給定一個 snake_case 識別名稱:

  1. 把每一段分隔符(底線、連字號、空白、點、斜線)換成單一 token 邊界。
  2. 把每個 token 轉成小寫,讓原始大小寫不再有影響。
  3. 對 camelCase,讓第一個 token 全小寫,並把之後每個 token 的第一個字母改大寫,中間不加分隔符。
  4. 對 PascalCase,把每個 token 的首字母大寫,同樣不加分隔符。
  5. 對 snake_case、kebab-case 與 CONSTANT_CASE,用對應的分隔符與大小寫把小寫 token 重新接起來。
  6. 對 Title Case,用空白連接並把每個 token 首字母大寫。

此規則從輸入 user_first_name 產出 camelCase 值 userFirstName、PascalCase 值 UserFirstName,以及 snake_case 值 user_first_name。同一規則套用到 API_RESPONSE_V2 會得到 apiResponseV2、ApiResponseV2、api_response_v2、api-response-v2、API_RESPONSE_V2,以及 Api Response V2。有意思的工作在步驟 1,分詞器在那裡決定一開始什麼算一個 token。

分詞正是多數轉換器失敗之處

網路上多數大小寫轉換器套用簡單 regex,通常類似 s.replace(/([A-Z])/g, '_$1').toLowerCase()。這種做法會把 XMLHttpRequest 變成 x_m_l_http_request,因為它在每個大寫字母前插入分隔符,包括縮寫裡的每一個字母。該輸入正確的分詞是 xml_http_request,有三個 token:xml、http、request。要把 XML 留在一起,需要一條規則能把一段大寫後面跟著一個首字母大寫的單詞辨認為縮寫邊界,而不是逐字母切開。

Camel Case 轉 Snake Case 轉換器依序套用兩條切分規則。首先在每個小寫到大寫轉換處切開,把 userId 裡的 c 與 I 分成 user 與 Id。然後在一段大寫與緊接其後的首字母大寫單詞之間的邊界切開,這就是把 XMLHttpRequest 裡的 XML 從 Http 拉開的做法。任何既不是 Unicode 字母也不是 Unicode 數字的連續字元,都會被當成分隔符並收成單一邊界,因此 snake_case、kebab-case 與 "snake case" 都會用同一方式分詞。在邊界允許的地方,數字留在它們所依附的 token 裡,因此 v2Endpoint 會變成 token v2 與 Endpoint,而不是 v、2、Endpoint。大小寫使用明確的英文 locale,因此結果不會在使用者 locale 設定不同的機器之間漂移。

輸入詞元camelCasesnake_case
user_first_nameuser, first, nameuserFirstNameuser_first_name
XMLHttpRequestxml, http, requestxmlHttpRequestxml_http_request
v2_api_endpointv2, api, endpointv2ApiEndpointv2_api_endpoint
kebab-case-thingkebab, case, thingkebabCaseThingkebab_case_thing

本工具的全部六種輸出都來自同一份 token 清單,因此把 camelCase 值再貼回轉換器,會得到相同的 snake_case、kebab-case 與 CONSTANT_CASE 值,不會漂移。這也是為什麼目標專案的縮寫政策很重要:userId 與 userID 分詞方式相同,兩者都會回來成 userId,而不是 userID,除非你的程式庫再手動把縮寫加回去。

在瀏覽器裡轉換 snake_case 識別名稱

  1. 把 snake_case 識別名稱、JSON 欄位名稱或短片語貼進 Camel Case 轉 Snake Case 轉換器的輸入框。
  2. 檢視輸入下方顯示的分詞清單。這一段決定 XML 是否留在一起、v2 是否仍貼在 endpoint 上,以及設定檔的標點是否變成空 token 而弄壞結果。
  3. 選 camelCase 輸出給 JavaScript 變數、函式與物件屬性。選 PascalCase 給類別與 React 元件,kebab-case 或 snake_case 給檔名,CONSTANT_CASE 給模組層常數與環境變數名稱,Title Case 給供人閱讀的標籤。
  4. 用每一列的複製控制複製所選值,貼進你正在編輯的檔案,並執行下一節所述的專案特定重新命名與相容性檢查。

輸入上限為五千個碼元,夠放長識別名稱或短片語,但不夠放整份檔案。空輸入或只有標點的輸入會被拒絕,因為沒有可轉換的 token。空白與重複分隔符會收合,而不是產生空詞。本工具完全透過 React 在你的瀏覽器裡執行,不執行貼上的內容、不上傳任何東西、不儲存任何東西,也不需要登入或安裝套件。

camelCase 在 JavaScript 程式庫裡該出現的位置

駝峰式是 JavaScript 識別名稱的主流風格,只要它們不是常數、類別或 React 元件。區域變數、函式名稱、以點記號存取的物件屬性、類別上的方法名稱,以及你從自己的 API 暴露的 JSON 鍵,慣例上都用 camelCase。PascalCase 保留給建構函式、ES 類別與 React 元件型別,好讓 JSX 標籤與類別名稱對齊。CONSTANT_CASE 用於模組層常數、組態開關,以及你也會從 shell 讀取的環境變數值。kebab-case 在原始檔裡很少見,因為連字號在 JavaScript 會被解讀成減號運算子,但它常見於檔名、以 slug 為基礎的路由,以及 JavaScript 會讀取的 CSS 類別名稱。

建構常見風格範例
區域變數camelCasecurrentUserId
函式或方法camelCasegetUserProfile
物件屬性camelCasefirstName
類別或 React 元件PascalCaseUserProfile
模組層常數CONSTANT_CASEMAX_RETRY_COUNT
URL slug 或 CSS 類別kebab-caseuser-profile-card

這些是慣例,不是語言規則。專案可能為了與後端對齊而要求 snake_case,或禁止識別名稱以數字開頭,或把識別名稱長度限制在資料庫欄位上限。轉換器的六種輸出是機械轉換,你仍須套用程式庫實際執行的政策。若要一次比較這六種風格,見 camel case 與 snake case 指南

專案範圍重新命名的考量

在單一檔案裡重新格式化一個識別名稱是安全的。在整個專案重新命名一個識別名稱則是另一件事。從套件匯出的公開符號、被其他服務讀取的資料庫欄位、被行動應用消費的 JSON 屬性、被部署指令碼讀取的環境變數,或被外部用戶端加入書籤的 URL 路徑,一旦拼法改變就會成為破壞性變更,即使新拼法看起來更乾淨。檔案系統與資料庫用各自的大小寫敏感規則比較識別名稱,因此只差大小寫的重新命名可能需要中間名稱,以免碰撞或遺失資料。

本工具只轉換文字。真正的重新命名,請對程式碼使用具備語言感知的重構工具、對欄位使用資料庫遷移、對 JSON 使用別名或相容欄位,並對 URL 使用重新導向或版本升級。合併前請跑型別檢查器、linter、測試套件,以及針對舊拼法的專案範圍搜尋。產生的程式碼、組態檔、ORM 模型,以及由 reflection 驅動的程式碼,可能握有連好的重新命名工具也看不到的參照,因此請讀 diff 並檢查部署順序。縮寫政策尤其值得注意:期望 userID 的專案可能不希望轉換器產出 userId,而那是專案決策,不是分詞器決策。

本工具會做與不會做的事

轉換器一次為一個識別名稱或短片語分詞,並回傳六種已公開的命名風格。它保留 Unicode 字母與數字、對大小寫套用明確的英文 locale 以免結果在機器間漂移、收合重複分隔符,並拒絕空輸入或只有標點的輸入。它不做文字轉寫、不變單複數、不拼字檢查、不保留標點,也不猜測語意縮寫。user_id_number 會變成 userIdNumber,絕不會變成專案特定的 userIDNumber。它不在你的編輯器裡執行、不 commit 到 git,也不跨儲存庫重新命名。若要在迭代時做 JavaScript 特定測試,JavaScript Playground 是實用的搭配,可在提交前用小型輔助函式試轉換後的值。

貼上符合你程式庫的值,跑專案已在用的格式化工具與型別檢查,並把這次重新命名當成部署變更而不是單純改名。全部在本機執行,輸入從不離開瀏覽器,使用時不需登入或套件。

若要更深入了解,見 在 JavaScript 把 HTML 轉成 DOCX:序列化步驟