JavaScript 字串操作:includes、startsWith、endsWith
簡介
在前端開發或 Node.js 後端程式中,字串是最常見的資料型別之一。無論是驗證使用者輸入、解析 API 回傳的文字,或是動態產生 UI,常都需要判斷字串是否包含特定子字串,或是以什麼字元開頭/結尾。
ECMAScript 6 為 String 物件新增了三個直觀且效能良好的方法:includes()、startsWith()、endsWith()。相較於舊式的 indexOf()、正規表達式等寫法,這三個方法語意更清楚、使用更安全,也更符合「可讀性」的程式設計原則。
本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,帶你全面掌握這三個字串方法,並提供實務上常見的應用情境,協助你在日常開發中寫出更簡潔、易維護的程式碼。
核心概念
1. String.prototype.includes(searchString, position?)
includes() 用來判斷 字串中是否出現 指定的子字串,回傳布林值 true 或 false。第二個參數 position(可選)表示搜尋的起始索引,預設為 0。
const text = "JavaScript 是最受歡迎的前端語言。";
// 基本用法
console.log(text.includes("受歡迎")); // true
// 指定起始位置
console.log(text.includes("前端", 20)); // false,因為從 index 20 開始找不到「前端」
// 若不提供 position,會從頭開始搜尋
小技巧:
includes()對空字串""永遠回傳true,因為任何字串都「包含」空字串。
2. String.prototype.startsWith(searchString, position?)
startsWith() 檢查 字串是否以 指定子字串開頭,同樣回傳布林值。position 參數允許你指定「從哪個位置開始當作字串的起點」進行檢查。
const url = "https://developer.mozilla.org/zh-TW/docs/Web/JavaScript";
// 判斷是否為安全的 https 網址
if (url.startsWith("https://")) {
console.log("安全連線");
}
// 從第 8 個字元開始檢查(跳過 "https://")
console.log(url.startsWith("developer", 8)); // true
注意:
startsWith()只會檢查 單一位置,不會搜尋整個字串。
3. String.prototype.endsWith(searchString, length?)
endsWith() 用於判斷 字串是否以 指定子字串結尾。第二個參數 length(可選)表示「視為字串的長度」,可用來在不改變原字串的情況下,只檢查子字串的前半部分。
const fileName = "report_2024.pdf";
// 檢查副檔名是否為 .pdf
console.log(fileName.endsWith(".pdf")); // true
// 只檢查前 12 個字元是否以 "_2024" 結尾
console.log(fileName.endsWith("_2024", 12)); // true
4. 為什麼要使用這三個方法?
| 方法 | 主要用途 | 相較於舊寫法的優勢 |
|---|---|---|
includes |
判斷是否包含子字串 | 語意清晰、避免 -1 判斷 |
startsWith |
判斷開頭 | 不必手動切片或使用正規表達式 |
endsWith |
判斷結尾 | 同上,且支援 length 參數 |
程式碼範例
以下提供 5 個實用範例,示範在不同情境下如何結合 includes、startsWith、endsWith。
範例 1:表單驗證 – 電子郵件格式檢查
function isValidEmail(email) {
// 必須同時包含 "@" 且以 ".com"、".org"、".net" 結尾
return email.includes("@") &&
(email.endsWith(".com") || email.endsWith(".org") || email.endsWith(".net"));
}
console.log(isValidEmail("test@example.com")); // true
console.log(isValidEmail("invalid-email")); // false
範例 2:路由權限判斷
function hasAccess(route) {
// 只允許以 "/admin" 開頭且不以 "/public" 結尾的路徑
return route.startsWith("/admin") && !route.endsWith("/public");
}
console.log(hasAccess("/admin/dashboard")); // true
console.log(hasAccess("/admin/public")); // false
範例 3:檔案類型過濾(多副檔名)
const allowedExt = [".png", ".jpg", ".jpeg", ".gif"];
function isImage(fileName) {
return allowedExt.some(ext => fileName.toLowerCase().endsWith(ext));
}
console.log(isImage("avatar.PNG")); // true
console.log(isImage("document.pdf")); // false
範例 4:搜尋功能 – 只在文字開頭顯示結果
const products = ["Apple iPhone", "Samsung Galaxy", "Google Pixel", "Apple Watch"];
function filterByPrefix(keyword) {
return products.filter(p => p.toLowerCase().startsWith(keyword.toLowerCase()));
}
console.log(filterByPrefix("apple")); // ["Apple iPhone", "Apple Watch"]
範例 5:多語系支援 – 判斷語系代碼是否在支援清單內
const supportedLang = ["en-US", "zh-TW", "ja-JP", "fr-FR"];
function isSupported(locale) {
// 檢查完整代碼或僅檢查語言前兩碼(如 "zh")
return supportedLang.includes(locale) ||
supportedLang.some(code => code.startsWith(locale.split("-")[0]));
}
console.log(isSupported("zh-TW")); // true
console.log(isSupported("zh")); // true(因為支援 zh-??)
console.log(isSupported("de")); // false
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
| 大小寫不一致 | includes、startsWith、endsWith 為 區分大小寫 的比較。 |
在比較前使用 toLowerCase() 或 toUpperCase() 正規化字串。 |
| 傳入非字串 | 若 searchString 不是字串,會自動呼叫 ToString,但可能產生意料外結果。 |
事先確保參數為字串,或使用 String(searchString) 強制轉型。 |
| 空字串的行為 | ''.includes('')、''.startsWith('')、''.endsWith('') 都回傳 true。 |
若不想讓空字串通過,額外檢查 searchString.length > 0。 |
position 參數的負值 |
position 為負值時會被視為 0,可能導致搜尋結果與預期不符。 |
使用 Math.max(0, position) 保障正確性。 |
| Unicode 正規化 | 某些 Unicode 字元(如結合音)在不同表示方式下可能不相等。 | 若需精確比對,先使用 String.prototype.normalize()。 |
最佳實踐:
- 明確命名:將判斷結果包裝成語意清楚的函式(如
isValidEmail),提升可讀性。 - 避免硬編碼:將檔案副檔名、語系代碼等陣列抽離為常數或設定檔,方便維護。
- 結合陣列方法:使用
some()、every()搭配字串方法,可寫出更具宣告性的條件式。 - 效能考量:若要在大量資料上重複檢查,先把常用的字串轉成小寫或正規化,減少重複運算。
實際應用場景
- 前端路由守衛:在單頁應用(SPA)中,使用
startsWith('/admin')判斷使用者是否正嘗試進入管理區,結合身份驗證機制決定是否導向登入頁。 - 檔案上傳驗證:透過
endsWith()檢查上傳檔案的副檔名,配合Array.some()篩選允許的類型,避免不安全檔案被寫入伺服器。 - 搜尋自動完成:在搜尋框即時顯示結果時,使用
startsWith()只列出以關鍵字開頭的項目,提升使用者體驗。 - 國際化 (i18n) 文字切換:根據使用者的瀏覽器語系(如
navigator.language),使用startsWith()判斷是否支援對應語系,決定載入哪套語系檔案。 - 內容過濾:在聊天室或評論系統中,利用
includes()快速檢測是否含有敏感詞彙,結合正規表達式做更精細的過濾。
總結
includes()、startsWith()、endsWith() 是 ES6 之後字串處理的核心工具,提供了直觀且效能佳的子字串檢查方式。透過本文的概念說明、實作範例與最佳實踐,你應該已能:
- 正確判斷字串是否包含、開頭或結尾指定文字。
- 處理大小寫、空字串與 Unicode 正規化等常見問題。
- 在表單驗證、路由守衛、檔案過濾、搜尋與國際化等實務情境中靈活運用。
掌握這三個方法後,未來在處理文字相關的需求時,你將能寫出 更簡潔、可讀性更高且更不易出錯 的程式碼。祝你在 JavaScript 的字串世界裡玩得開心,也期待看到你把這些技巧帶入實際專案中!