(JS基礎)String 型別

hozee的個人筆記發表於2019-04-20

我們對字串型別的資料並不會陌生。let str = 'value'就是一個最簡單的生成字串例子。

我們還可以通過String(thing)new String(thing)將任何型別的資料轉化成字串。

例如,把一個空物件傳入,String({})返回的值為"[object Object]",這裡不得不提的就是,其他型別預設的toString()方法本質就是呼叫String({})

字串量能直接使用String的屬性和方法,如'string'.toLowerCase()。其實語言內部會將'string'封裝成物件,再執行相應的方法,最後字串物件使用valueOf()toString()方法得到字串的值。


屬性

常用屬性只有一個:length,返回字串的長度

方法

以下介紹的,除了String​.raw()為靜態方法,其他都是字串物件的方法。所有的字串方法都不會對原字串修改,都是返回一個新的字串或結果。

拼接/補全

查詢

擷取

轉換大小寫

字元碼點

  • normalize([form]):按照指定的一種 Unicode 正規形式將當前字串正規化form預設為 "NFC"。例子:'\u01D1'.normalize() === '\u004F\u030C'.normalize();  // true
  • charCodeAt():

內建迭代器([Symbol.iterator])

String物件內建Iterator物件,通過屬性[Symbol.iterator]獲取,在遍歷時呼叫,如for...of運算、展開運算子(...)等。

獲取迭代器

let strIterator = 'abcde'[Symbol.iterator]();
console.log(strIterator.next().value);  // 'a'
console.log(strIterator.next().value);  // 'b'
console.log(strIterator.next().value);  // 'c'複製程式碼

修改迭代器

// 必須建立字串物件
let str = new String('abcde');
// 原生迭代器效果
for (let i of str) {
  console.log(i);
}
// 列印結果: a  b  c  d  e
// 自定義迭代器函式
str[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
}
// 測試自定義迭代器
console.log(...str);  // 1 2 3複製程式碼


字串模板(Template literals)

字串模板用"反引號"表示,即 ` `

基本用法

模板字串內,字串量可以直接寫,${ }內執行JavaScrip程式碼。用於生成一個帶運算的字串結果。

let num1 = 123,
  num2 = 456;
let temp = `hello ${num1 + num2} world !`;
console.log(temp);    // "hello 579 world !"複製程式碼

標籤模板(Tagged templates)用法

我們一般呼叫函式的方式是fn(['hello ', 'world'], 999),函式名後用括號包裹引數。而標籤模板可以這樣寫:fn`hello ${args}world`,函式名後直接跟``。注意,這兩種方式的引數是一致的。

分解:

${ }的模板字串,內部其實是被${}分割成多份。以`hello ${999}world${666} !`為例:

`
hello 
${999}
world
${666} 
!
`複製程式碼

${ }的外面是字串直接量,而${ }之間是 js 程式碼。如此看來,字串模板被分成了 5 份,而字串直接量會組成字串陣列,所以傳入函式時是 3 個引數,分別是['hello ', 'world', ' !']999666。下面給出簡單例子說明。

// 用於檢視傳參情況的函式
function fn() {
  console.log(arguments[0])
}
fn`hello ${999}world${666} !`;
// 下圖看結果複製程式碼

(JS基礎)String 型別

String​.raw()

談到模板字串,不得不談String物件的一個靜態方法:String​.raw()。一般都是以標籤函式的方式呼叫它,即String​.raw``,當然,你可以使用普通函式的()方式傳參,只不過要按照上面額規則手動轉化一下。它的用途是獲取一個模板字串的原始字面量值,簡單說就是把所有的反斜槓(\)轉義。

String.raw `Hi\u000A!`;      // "Hi\\u000A!"
String.raw `Hi\n${999}!`;    // "Hi\\n999!"
String.raw`\\`;              // "\\\\"
複製程式碼


字元編碼與字符集

基本概念

  1. 字元,是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。
  2. 字型檔表,是一個相當於所有可讀或者可顯示字元的資料庫,字型檔表決定了整個字符集能夠展現表示的所有字元的範圍。其實就是字元的集合
  3. 編碼字符集,簡稱字符集,用一個編碼值code point(又稱碼點)來表示一個字元(即該字元在子庫表中的位置),這個值稱為字元對應於編碼字符集(如:Unicode、ASCII)的序號。
  4. 字元編碼,是編碼字符集和實際儲存數值之間的轉換關係。

用商場儲物櫃為例子。

字元,等於單個櫃箱,存放著我們想看的內容。

整個儲物櫃就是字型檔表

為每個櫃箱按順序貼上標籤後,整個儲物櫃就是編碼字符集,每個數字(碼點)對應一個櫃箱(字元)。

我們手上有一份查詢表格,但表格上只能寫二進位制或十六進位制的數字。以什麼樣的方式把儲物櫃上的數字對應到表格上(對映),就是字元編碼

ASCII

ASCII 既是字符集,也是字元編碼。用一個位元組的長度儲存字元。自行百度,不多介紹。

Unicode

Unicode 是一個字符集,為每個符號指定一個編號,即"碼點"(code point)。其目標是將全世界所有的字元包含在一個集合裡,計算機只要支援這一個字符集,就能顯示所有的字元。

每個區可以存放 65536 個(216)字元,稱為一個平面(plane)。

目前,一共有 17 個(25)平面,也就是說,整個 Unicode 字符集的大小現在是 221

最前面的 65536 個字元位,稱為基本平面(縮寫 BMP ),它的碼點範圍是從 0 一直到 216-1 ,寫成 16 進位制就是從 U+0000 ~ U+FFFF

剩下的字元都放在輔助平面(縮寫 SMP ),碼點範圍為 U+010000 ~ U+10FFFF

UTF-32

UTF-32 是字元編碼方式,用固定長度的 4 位元組表示一個字元,與 Unicode 位元組內容一一對應碼點。例如:

U+597D = 0x0000 597D複製程式碼

但缺點很明顯,浪費空間。HTML5 標準就明文規定,網頁不得編碼成UTF-32。

UTF-8

UTF-8 是一種變長的編碼方法,字元長度從 1 個位元組到 4 個位元組不等。越是常用的字元,位元組越短,最前面的 128 個字元,只使用 1 個位元組表示,與 ASCII 碼完全相同。如,編碼範圍在0x0000 - 0x007F只佔用 1 位元組,而0x010000 - 0x10FFFF要佔用 4 位元組。是最常見的網頁編碼。

由於 UTF-8 是變長的,若不直到其長度,連續的字元則無法解析。如何判斷其長度,這就涉及它的編碼規則

  1. 對於單位元組的符號,第一位為 0 ,用二進位制表示為0xxx xxxx
  2. 對於n位元組的符號(n>1),第一個位元組的前n位都設為1,第n+1位設為0,後面位元組的前兩位一律設為10。剩下的沒有提及的二進位制位,全部為這個符號的unicode碼。

阮一峰的博文的圖表展示:

Unicode 符號範圍 (十六進位制) UTF-8 編碼方式 (二進位制) 位元組
0000 0000-0000 007F 0xxxxxxx 1
0000 0080-0000 07FF 110xxxxx 10xxxxxx 2
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 3
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4

圖表中x組合而成的就是實際的 Unicode 碼點。

UTF-16

UTF-16 編碼介於 UTF-32 與 UTF-8 之間,同時結合了定長和變長兩種編碼方法的特點。編碼規則就是,基本平面的字元佔用 2 個位元組輔助平面的字元佔用 4 個位元組

因為在基本平面內,從U+D800 ~ U+DFFF是一個空段,空間為 211 ,即 2 個 210 。而一個輔助平面的字元需要的空間為 220 ,剛好可以拆分成兩個空段內的字元,高位(H)對映在U+D800 ~ U+DBFF低位(L)對映在U+DC00 ~ U+DFFF。因此解決了 4 位元組的字元的識別問題。

所以,對於基本平面,Unicode 與 UTF-16 碼相同。

對於輔助平面,Unicode 與 UTF-16 的轉化公式如下:

H = Math.floor((c-0x10000) / 0x400) + 0xD800
L = (c - 0x10000) % 0x400 + 0xDC00複製程式碼

不難理解,輔助平面的碼點是從U+10000開始,則減去0x10000;上面提到高低位各佔 10 位,則除以0x400得到的商和餘數則分別位高低位的起點值,最後高位加上基礎值0xD800,低位加上0xDC00得到目標值。(內容總結自阮一峰的博文

JavaScript 使用的編碼方式

JavaScript 語言採用 Unicode 字符集,但是隻支援一種編碼方法,就是 UCS-2 。由於歷史原因(阮一峰的博文有介紹),UCS-2 只支援 2 位元組的字元,4 位元組的字元被當成 2 個 2 位元組的字元解析。現在已經沒有 UCS-2 。

ES6 增強對 Unicode 的支援

  1. ES6 可以自動識別 4 位元組的碼點,如console.log('\ud834\udf06');  // ?
  2. 允許直接用碼點表示Unicode字元,如'?' === '\u{1d306}';  // true。2 位元組的字元可以省略{}
  3. ES6 新增了幾個專門處理 4 位元組碼點的函式(看上方)。
  4. ES6 提供了u修飾符,對正規表示式新增4位元組碼點的支援。


相關文章