# JavaScript 入門課程 - 第二章 資料型別(Data type) 2-4 字串(String) [竹白記事本](https://chupainotebook.blogspot.com/),學習筆記整理 2019/01/16。 ###### tags: `JavaScript 入門課程` `JavaScript` `JavaScript 入門課程 - 第二章 資料型別(Data type)` >學習書本: >[JavaScript 教程電子書|作者:阮一峰老師](https://wangdoc.com/javascript/index.html) 「JavaScript 教程」是由阮一峰老師所撰寫的,並且授權方式為「知識共享署名-相同方式共享3.0協議」,非常適合初學者當作 JavaScript 語言的入門課程。 ## [目錄](https://hackmd.io/zZe_oRgfQp6YFboDCVAvpg) * Ch2 資料型別(Data type) * [2-1 概述](https://hackmd.io/s/Hkr0vljfV) * [2-2 null、undefined 和 布林值(Boolean)](https://hackmd.io/s/Hkr0vljfV) * [2-3 數值(Number)](https://hackmd.io/s/rkJlPqsGV) * [2-4 字串(String)](https://hackmd.io/s/HJvOP5iGE) * [2-5 物件(Object)](https://hackmd.io/s/H1Aq7D3f4) * [2-6 函式(Function)](https://hackmd.io/s/S1ls7D3zE) * [2-7 陣列(Array)](https://hackmd.io/s/BkzjmP3GE) # 2-4 字串(String) ## 1. 概述 ### 1.1 定義 字串就是零個或多個排在一起的字符,放在單引號或雙引號之中。 ```javascript 'abc' "abc" ``` 單引號字串的內部,可以使用雙引號。雙引號字串的內部,可以使用單引號。 ```javascript 'key = "value"' "It's a long journey" ``` 上面兩個都是合法的字串。 如果要在單引號字串的內部,使用單引號,就必須在內部的單引號前面加上反斜杠,用來轉義。雙引號字串內部使用雙引號,也是如此。 ```javascript 'Did she say \'Hello\'?' // "Did she say 'Hello'?" "Did she say \"Hello\"?" // "Did she say "Hello"?" ``` :::success 由於 HTML 語言的屬性值使用雙引號,所以很多項目約定 JavaScript 語言的字串只使用單引號,本教程遵守這個約定。當然,只使用雙引號也完全可以。重要的是堅持使用一種風格,不要一會使用單引號表示字串,一會又使用雙引號表示。 ::: 字串默認只能寫在一行內,分成多行將會報錯。 ```javascript 'a b c' // SyntaxError: Unexpected token ILLEGAL ``` 上面代碼將一個字串分成三行,JavaScript 就會報錯。 如果長字串必須分成多行,可以在每一行的尾部使用反斜杠。 ```javascript var longString = 'Long \ long \ long \ string'; longString // "Long long long string" ``` 上面代碼表示,加了反斜杠以後,原來寫在一行的字串,可以分成多行書寫。但是,輸出的時候還是單行,效果與寫在同一行完全一樣。注意,反斜杠的後面必須是換行符,而不能有其他字符(比如空格),否則會報錯。 連接運算子(`+`)可以連接多個單行字串,將長字串拆成多行書寫,輸出的時候也是單行。 ```javascript var longString = 'Long ' + 'long ' + 'long ' + 'string'; // "Long long long string" ``` :::warning 目前 ES6 新增了新的符號,可以將字串分成多行輸出。 ::: ```javascript var longString = ` Long 123 abc ` // " // Long // 123 // abc // " ``` ### 1.2 轉義 反斜杠(`\`)在字串內有特殊含義,用來表示一些特殊字符,所以又稱為轉義符。 需要用反斜杠轉義的特殊字符,主要有下面這些。 - `\0` :null(`\u0000`) - `\b` :後退鍵(`\u0008`) - `\f` :換頁符(`\u000C`) - `\n` :換行符(`\u000A`) - `\r` :回車鍵(`\u000D`) - `\t` :製表符(`\u0009`) - `\v` :垂直製表符(`\u000B`) - `\'` :單引號(`\u0027`) - `\"` :雙引號(`\u0022`) - `\\` :反斜杠(`\u005C`) 上面這些字符前面加上反斜杠,都表示特殊含義。 ```javascript console.log('1\n2') // 1 // 2 ``` 上面代碼中,`\n` 表示換行,輸出的時候就分成了兩行。 反斜杠還有三種特殊用法: (1)`\HHH` 反斜杠後面緊跟三個八進制數(`000` 到 `377`),代表一個字符。`HHH` 對應該字符的 Unicode 碼點,比如 `\251` 表示版權符號。顯然,這種方法只能輸出 256 種字符。 (2)`\xHH` `\x` 後面緊跟兩個十六進制數(`00` 到 `FF`),代表一個字符。`HH` 對應該字符的 Unicode 碼點,比如 `\xA9` 表示版權符號。這種方法也只能輸出 256 種字符。 (3)`\uXXXX` `\u` 後面緊跟四個十六進制數(`0000` 到 `FFFF`),代表一個字符。`XXXX` 對應該字符的Unicode 碼點,比如 `\u00A9` 表示版權符號。 ```javascript '\251' // "©" '\xA9' // "©" '\u00A9' // "©" '\172' === 'z' // true '\x7A' === 'z' // true '\u007A' === 'z' // true ``` 如果在非特殊字符前面使用反斜杠,則反斜杠會被省略。 ```javascript '\a' // "a" ``` 上面代碼中,`a` 是一個正常字符,前面加反斜杠沒有特殊含義,反斜杠會被自動省略。 如果字串的正常內容之中,需要包含反斜杠,則反斜杠前面需要再加一個反斜杠,用來對自身轉義。 ```javascript "Prev \\ Next" // "Prev \ Next" ``` ### 1.3 字串與陣列 字串可以被視為字符陣列,因此可以使用陣列的方括號運算子,用來傳回某個位置的字符(位置編號從 0 開始)。 ```javascript var s = 'hello'; s[0] // "h" s[1] // "e" s[4] // "o" // 直接對字串使用方括號運算子 'hello'[1] // "e" ``` 如果方括號中的數字超過字串的長度,或者方括號中根本不是數字,則傳回 `undefined`。 ```javascript 'abc'[3] // undefined 'abc'[-1] // undefined 'abc'['x'] // undefined ``` 但是,字串與陣列的相似性僅此而已。實際上,無法改變字串之中的單個字符。 ```javascript var s = 'hello'; delete s[0]; s // "hello" s[1] = 'a'; s // "hello" s[5] = '!'; s // "hello" ``` 上面代碼表示,字串內部的單個字符無法改變和增刪,這些操作會默默地失敗。 ### 1.4 length 屬性 `length` 屬性傳回字串的長度,該屬性也是無法改變的。 ```javascript var s = 'hello'; s.length // 5 s.length = 3; s.length // 5 s.length = 7; s.length // 5 ``` 上面代碼表示字串的 `length` 屬性無法改變,但是不會報錯。 ## 1.5 字符集 JavaScript 使用 Unicode 字符集。JavaScript 引擎內部,所有字符都用 Unicode 表示。 JavaScript 不僅以 Unicode 儲存字符,還允許直接在程序中使用 Unicode 碼點表示字符,即將字符寫成 `\uxxxx` 的形式,其中 `xxxx` 代表該字符的 Unicode 碼點。比如, `\u00A9`代表版權符號。 ```javascript var s = '\u00A9'; s // "©" ``` 解析代碼的時候,JavaScript 會自動識別一個字符是字面形式表示,還是 Unicode 形式表示。輸出給用戶的時候,所有字符都會轉成字面形式。 ```javascript var f\u006F\u006F = 'abc'; foo // "abc" ``` 上面代碼中,第一行的變數名 `foo` 是 Unicode 形式表示,第二行是字面形式表示。JavaScript 會自動識別。 我們還需要知道,每個字符在 JavaScript 內部都是以 16 位(即 2 個字節)的 UTF-16 格式儲存。也就是說,JavaScript 的單位字符長度固定為 16 位長度,即 2 個字節。 但是,UTF-16 有兩種長度:對於碼點在 `U+0000` 到 `U+FFFF` 之間的字符,長度為 16 位(即 2 個字節);對於碼點在 `U+10000 ` 到 `U+10FFFF` 之間的字符,長度為 32 位(即 4 個字節),而且前兩個字節在 `0xD800` 到 `0xDBFF` 之間,後兩個字節在 `0xDC00` 到 `0xDFFF` 之間。舉例來說,碼點 `U+1D306` 對應的字符為 `𝌆` ,它寫成 UTF-16 就是 `0xD834 0xDF06`。 JavaScript 對 UTF-16 的支持是不完整的,由於歷史原因,只支持兩字節的字符,不支持四字節的字符。這是因為 JavaScript 第一版發布的時候,Unicode 的碼點只編到 `U+FFFF`,因此兩字節足夠表示了。後來,Unicode 納入的字符越來越多,出現了四字節的編碼。但是,JavaScript 的標準此時已經定型了,統一將字符長度限制在兩字節,導致無法識別四字節的字符。上一節的那個四字節字符 `𝌆`,瀏覽器會正確識別這是一個字符,但是JavaScript 無法識別,會認為這是兩個字符。 ```javascript '𝌆'.length // 2 ``` 上面代碼中,JavaScript 認為 `𝌆` 的長度為 2,而不是 1。 總結一下,對於碼點在 `U+10000` 到 `U+10FFFF` 之間的字符,JavaScript 總是認為它們是兩個字符(`length` 屬性為 2)。所以處理的時候,必須把這一點考慮在內,也就是說,JavaScript 傳回的字串長度可能是不正確的。 ## 3. Base64 轉碼 有時,文本中包含一些不可打印的符號,比如 ASCII 碼 0 到 31 的符號都無法打印出來,這時可以使用 Base64 編碼,將它們轉成可以打印的字符。另一個場景是,有時需要以文本格式傳遞二進制資料,那麼也可以使用 Base64 編碼。 所謂 Base64 就是一種編碼方法,可以將任意值轉成 0~9、A~Z、az、`+` 和 `/` 這 64 個字符組成的可打印字符。使用它的主要目的,不是為了加密,而是為了不出現特殊字符,簡化程序的處理。 JavaScript 原生提供兩個 Base64 相關的方法。 - `btoa()`:任意值轉為 Base64 編碼 - `atob()`:Base64 編碼轉為原來的值 ```javascript var string = 'Hello World!'; btoa(string) // "SGVsbG8gV29ybGQh" atob('SGVsbG8gV29ybGQh') // "Hello World!" ``` 注意,這兩個方法不適合非 ASCII 碼的字符,會報錯。 ```javascript btoa('你好') // 報錯 ``` 要將非 ASCII 碼字符轉為 Base64 編碼,必須中間插入一個轉碼環節,再使用這兩個方法。 ```javascript function b64Encode(str) { return btoa(encodeURIComponent(str)); } function b64Decode(str) { return decodeURIComponent(atob(str)); } b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE" b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好" ``` --- 下個章節:[2-5 物件(Object)](https://hackmd.io/s/H1Aq7D3f4)