這些年,我錯過的 JavaScript 字串函數
2 |
前幾天幫同事看問題,要在 JavaScript 偵測 location.href 是否為 / 字元結尾,看到 Visual Studio 自動提示了 endsWith() 函式,大驚!
JavaScript 不知何時早已內建 startsWith、endsWith (Chrome 41 就有,目前版號都破百了),我居然還傻傻用 s.indexOf('/') == 0、s.lastIndexOf('/') == s.length -1 或是 /^\//.exec(s) 檢查。
我在瀏覽器寫法 JavaScript 一向很保守,這跟我一直在維護 IE 古蹟有關,看到新語法往往潛意識會跳過,因為即使在 IE11 都未必支援(未來也不會支援,因為 IE 沒有未來了),知道好方法又不能用更痛苦 XD。像開頭提到的 startsWith(),就不在 IE 支援之列:參考
為避免程式用新語法在 IE 爆炸,老寫法笨歸笨,但保證相容,造就我不熱衷學習 JavaScript 新語法的心態。如今,野生 IE 即將滅絕(將於 2022/6/15 EOS),企業內部人工飼養 IE 預估可用到 2029 但應會漸以 Edge 為主或有 Chrome 並行 (延伸閱讀:古蹟維護小組觀點 - IE 大限揭曉,這下總算 封印解除 ,可以大方使用新一代的前端技術惹。
(照片作者:Evan)
這次事件讓我想到該重新檢視 JavaScript API,看看這些年自己因為 IE 錯過哪些好用的新方法,就從字串開始吧。
要查 String 有哪些 API,當然是看 MDN 囉!
看了一輪 String 方法列表,跳過用到爛的 indexOf、lastIndexOf、toUpperCase、substr、substring,聚焦我不熟或遺漏隱藏用法的項目,整理範例如下:
<!DOCTYPE html>
<html>
<head>
<style>
.t {
display: inline-block; width: 100px; padding: 3px;
color: white; background-color: cornflowerblue;
text-align: right; margin-bottom: 2px;
}
</style>
</head>
<body>
<pre id="d"></pre>
<script>
function log(t, m) {
document.getElementById('d').innerHTML +=
`<span class=t>${t}</span> <span>${m}</span>` + '\n';
}
function logEval(t, exp) {
log(t, exp + ` => ${eval(exp)}`);
}
const s = "This is a book.";
log('string', `let s="${s}"`);
// at() 取第 n 個字元,類似 charAt 但可用負數
logEval('at()', `s.at(2)`);
logEval('at()', `s.at(-5)`);
// charCodeAt() 取第 n 個字元的 UTF-16(ASCII) 碼
logEval('charAt()', `s.charAt(2) + "->" + s.charCodeAt(2)`);
// codePointAt() 可用轉換成  
const c = '\ua66c';
const unicodeCodePoint = c.codePointAt(0);
log('codePointAt()', `${c} -> &#${unicodeCodePoint}; &#${unicodeCodePoint};`);
logEval('concat()', `"hello".concat(" ", "world", "!")`);
// 相當於 C# string.Contains()
logEval('includes()', `"Smiles".includes("mile")`)
logEval('startsWith()', `"darkthread".startsWith("dark")`);
logEval('endsWith()', `"darkthread".endsWith("a")`);
logEval('match()', `JSON.stringify("192.168.1.1".match(/\\d{1,3}/))`);
logEval('match()', `JSON.stringify("192.168.1.1".match(/\\d{1,3}/g))`);
// 數字補零很好用
logEval('padStart()', `"12345".padStart(7, '0')`);
logEval('padEnd()', `"1234".padEnd(7, "#")`);
logEval('repeat()', `"A".repeat(10)`);
logEval('replace()', `"A1B2C3D4E5".replace("B2", "")`);
logEval('replace()', `"A1B2C3D4E5".replace(/[a-z]/ig, "")`);
logEval('search()', `"secret number 123 inside".search(/\\d/)`);
logEval('slice()', `"pen pineapple apple pen".slice(4)`);
logEval('slice()', `"pen pineapple apple pen".slice(-3)`);
logEval('slice()', `"pen pineapple apple pen".slice(4, 7)`);
logEval('split()', `"pen pineapple apple pen".split(' ')`);
// trim* 只去除空白,去頭尾非空白字元要用 replace + regular expression
logEval('trim()', `"[" + " HELLO ".trim() + "]"`);
logEval('trimStart()', `"[" + " HELLO ".trimStart() + "]"`);
logEval('trimEnd()', `"[" + " HELLO ".trimEnd() + "]"`);
logEval('Trim ending /', `"~/subdir/".replace(/\\/$/g, '')`);
// String("1+2") 與 "1+2" 行為有些不同,
logEval('valueOf()', `typeof(new String("1+2"))`);
logEval('valueOf()', `eval(new String("1+2"))`);
logEval('valueOf()', `new String("1+2").valueOf()`);
logEval('valueOf()', `eval(new String("1+2").valueOf())`);
</script>
</body>
</html>
檢閱完畢。
Needing to support IE, I missed some JavaScript handy methods. This notes enumerate the functions I missed in these years.
Comments
# by Huang
一看到IDE有提示就可以用了
# by slash
寫了20年的程式,我也覺得JS的substring()何須看文件,就不信還能變出甚麼花樣?直到那天我膝蓋中了一箭...