Learning Objectives
- 用單引號、雙引號與樣板字面值建立字串,處理字串裡的引號
- 使用跳脫字元 \n、\t、\\,以及 \x、\u 的十六進位與 Unicode 表示法
- 用 length、索引、indexOf、includes 找到字串裡的內容
- 用 slice、split、join、trim、replace、replaceAll 等方法處理字串,並說明字串不可變
字串:文字資料
字串(string)用來表示文字:姓名、訊息、網址、從表單讀進來的資料都是字串。字串裡的每個字元都有一個位置(索引,index), 第一個字元的索引是 0,第二個是 1,依此類推。
建立字串有三種寫法:
| 寫法 | 例子 | 說明 |
|---|---|---|
| 單引號 | 'Hello' |
和雙引號完全一樣,選一種在專案裡統一即可 |
| 雙引號 | "Hello" |
|
| 反引號(樣板字面值) | `Hello ${name}` |
ES2015 加入,可以嵌入運算式、直接換行 |
引號要成對:'Mike's pet' 會出錯,因為第二個單引號就把字串結束了,後面的 s pet' 變成看不懂的程式碼(SyntaxError)。解決方法:
- 換一種外層引號:
"Mike's pet"、'He said "Hi"' - 用反斜線跳脫:
'Mike\'s pet'
JavaScript 的字串使用 Unicode,中文、日文、阿拉伯文等各國文字都可以直接寫在字串裡。
另外也有 new String('Hello') 這種「字串物件」的寫法,一般不需要使用,直接寫字串即可。
跳脫字元
跳脫字元(escape character)是反斜線 \:它告訴 JavaScript,下一個字元不是原本的意思。
| 寫法 | 意思 |
|---|---|
\n |
換行 |
\t |
Tab(定位字元) |
\'、\" |
字串裡的單引號、雙引號 |
\\ |
反斜線本身 |
\x41 |
十六進位的字元碼,\x41 是 A(ASCII 編碼) |
\u2661 |
Unicode 字元,\u 後面接 4 位十六進位:\u2661 是 ♡、\u4f60\u597d 是「你好」 |
\u{1F600} |
超過 4 位的 Unicode 字元(例如表情符號)用大括號(ES2015) |
最容易出錯的是 Windows 的檔案路徑:'c:\home' 裡的 \h 不是合法的跳脫序列,反斜線會被吃掉,印出 c:home。
要表示反斜線本身,必須寫兩個:'c:\\home'。
只寫一個反斜線的 "\" 是語法錯誤:反斜線把後面的引號跳脫了,字串沒有結束。
引號與跳脫字元
對照程式和輸出:第 9、10 行看起來幾乎一樣,印出來卻不同。最後一行的表情符號,length 為什麼是 2?
樣板字面值
用 + 把變數和文字接在一起,引號和加號一多就很難讀。樣板字面值(template literal)用反引號 ` 包住字串,
${ } 裡可以放任何運算式:變數、算式、函式呼叫、三元運算子,結果會轉成字串放進去。
const name = 'Amy';
console.log('你好,' + name + '!'); // 舊寫法
console.log(`你好,${name}!`); // 樣板字面值
樣板字面值也可以直接換行,不必寫 \n,適合組出多行的文字。
用樣板字面值組字串
第 6、7 行印出完全相同的內容,比較兩種寫法哪一種好讀。第 10~11 行的字串跨了兩行。
想一想:引號、跳脫與樣板字面值
下列哪一行會出現語法錯誤?
下面的程式會印出什麼?
console.log('a\nb'.length);
下面的程式會印出什麼?
const n = 3;
console.log(`共 ${n * 2} 個`);
長度、索引與搜尋
| 寫法 | 回傳 | 例子(s = 'hello') |
|---|---|---|
s.length |
字元數 | 5 |
s[0]、s[4] |
該位置的字元;超出範圍得到 undefined |
'h'、'o' |
s.at(-1) |
負數從後面數(ES2022) | 'o' |
s.indexOf('l') |
第一次出現的位置;找不到是 -1 |
2 |
s.lastIndexOf('l') |
最後一次出現的位置 | 3 |
s.includes('ell') |
有沒有包含(ES2015),回傳布林值 | true |
s.startsWith('he')、s.endsWith('lo') |
開頭、結尾是不是 | true、true |
s.search(/[a-z]/) |
用正規表示法找位置(j22 介紹) | 0 |
搜尋都分大小寫:'JavaScript'.includes('java') 是 false。
字串不可變(immutable):字串建立之後內容就不能改。s[0] = 'H' 不會出錯,但也不會有任何效果(嚴格模式下會出現 TypeError)。
toUpperCase()、replace() 這些方法都是回傳一個新字串,原本的字串不變;要改,就把新字串指定回變數。
索引、長度與「字串不可變」
看第 6 行:想把第一個字改成大寫 H。執行之後,右邊框架裡的 word 有沒有變?再看第 9 行 toUpperCase() 之後,word 本身變了沒有。
找位置與判斷是否包含
字串 txt 有兩個「課」字。先數一數第一個「課」的索引是多少,再看第 4 行的結果。
擷取、切割與去除空白
| 方法 | 說明 | 例子(s = 'JavaScript') |
|---|---|---|
s.slice(開始, 結束) |
從「開始」取到「結束」之前;可以用負數從後面算 | s.slice(0, 4) → 'Java'、s.slice(-6) → 'Script' |
s.substring(開始, 結束) |
和 slice 類似,但不接受負數,兩個參數會自動交換成小的在前 | s.substring(4, 0) → 'Java' |
s.split(分隔字串) |
切成陣列 | 'a,b'.split(',') → ['a', 'b'] |
陣列.join(連接字串) |
把陣列接回字串(陣列的方法) | ['a', 'b'].join('-') → 'a-b' |
s.trim() |
去掉前後空白;trimStart()、trimEnd() 只去一邊 |
' hi '.trim() → 'hi' |
substr(開始, 長度) 是舊方法,第二個參數是「長度」而不是結束位置。它只列在 ECMAScript 規格的附錄 B(為了相容舊網頁而保留的功能),
MDN 標示為不建議使用,新程式請用 slice。
slice、split、join 與 trim
第 3、4 行的 slice 用了正數與負數。第 8 行把一筆以逗號分隔的資料切成陣列,右邊會畫出這個陣列。
取代與大小寫
| 方法 | 說明 |
|---|---|
s.replace(舊, 新) |
只取代第一個符合的地方 |
s.replaceAll(舊, 新) |
取代全部符合的地方(ES2021) |
s.toUpperCase()、s.toLowerCase() |
英文字母轉大寫、小寫 |
s.repeat(次數) |
重複幾次 |
s.padStart(長度, 補的字) |
長度不足時在前面補字,常用來補零(padEnd 補在後面) |
在 replaceAll 出現之前,要全部取代必須用正規表示法 s.replace(/舊/g, '新'),舊程式碼裡很常見(j22 介紹)。
這些方法都回傳新字串,所以可以接著呼叫下一個方法:s.trim().toLowerCase().replaceAll(' ', '-')。
replace、replaceAll 與串接方法
msg 裡有兩個 XXX。比較第 3、4 行:replace 換了幾個?第 5 行再印一次 msg,它被改掉了嗎?
想一想:字串方法
下面的程式會印出什麼?
const s = 'JavaScript';
console.log(s.slice(-6, -3), s.indexOf('a'), s.includes('script'));
下面的程式會印出什麼?
let s = 'abc';
s.toUpperCase();
console.log(s);
下面的程式會印出什麼?
console.log('a-b-c'.replace('-', '+'), 'a-b-c'.split('-').length);
要從 '2026-10-30' 取出月份 '10',下列哪一個寫法不建議用在新程式?
實作:取代文字並計算長度
投影片 LAB03 的改寫:把字串裡所有的 XXX 換成「小明」、javascript 換成 JavaScript,印出結果,再印出新字串的長度。記得字串不可變,取代的結果要存回變數。
重點精華回顧
- 字串用單引號、雙引號或反引號建立;索引從 0 開始,
length是字元數。 - 反斜線
\是跳脫字元:\n換行、\tTab、\\反斜線本身、\x41十六進位、\u2661Unicode。 - 樣板字面值
`…${運算式}…`可以嵌入任何運算式,也可以直接換行。 - 找位置:
indexOf、lastIndexOf(找不到是 -1)、search;判斷包含:includes、startsWith、endsWith。 - 擷取用
slice(可負數)或substring;substr是舊方法不建議使用。切割與合併用split、join,去空白用trim。 replace只換第一個、replaceAll全部換;字串不可變,所有方法都回傳新字串。