ES6 學習筆記 - 字符串

本文知識點主要整理自《深刻理解 ES6(Understanding ECMAScript 6)》中文版實體書的內容,部分地方會加上本身的理解,同時書中敘述比較模糊的部分參考了阮一峯老師的《ECMAScript 6 入門》與網絡上其餘大佬們的博客、問答,篇幅有限沒法一一列出,在此表示感謝。javascript

更好的 Unicode 支持

UTF-16 碼位與 ES5 的缺陷

Unicode 是計算機領域內的一項業界標準,它對世界上大部分的文字系統進行了整理、編碼,目的是爲世界上每個字符提供全球惟一的標識符。Unicode 有兩個步驟,一是給字符規定一個惟一對應的數字;二是將字符對應的數字保存在計算機中。html

Unicode 對字符的惟一標識被稱爲碼位(code point)。JavaScript 的字符串一直是基於 UTF-16 進行構建,每 16 位的序列視爲一個編碼單元(code unit),表明一個字符。而且 lengthcharAt() 等字符串的屬性與方法都是基於這種編碼單元構造的。java

在 UTF-16 中,字符編碼空間由 U+0000U+10FFFF 一共 1112064 個碼位。同時編碼空間一共分爲 17 個平面(plane),每個平面包含 U+xx0000U+xxFFFF 一共 65536 個碼位。而第一個平面(U+0000U+FFFF)被稱爲 基本多文種平面(Basic Multilingual Plane,簡稱 BMP)。其餘平面被稱爲 輔助平面git

在早期 16 位足以包含任何字符,但隨着計算機的發展,更多語言與符號的加入,16 位已經不夠用,所以 UTF-16 加入了代理對(surrogate pair),其規定用兩個 16 位編碼單元表示一個碼位。es6

所以,UTF-16 中有兩種字符github

  • 由一個編碼單元 16 位表示的 BMP 字符
  • 由兩個編碼單元 32 爲表示的輔助平面字符

在 ES5 中,若是遇到包含代理對的 UTF-16 字符可能會獲得與預期不符的結果。正則表達式

const text = '𠮷'; // \uD842\uDFB7

console.log(text.length); // 2
console.log(text.charAt(0)); // ''
console.log(text.charAt(1)); // ''
console.log(text.charCodeAt(0)); // 55362
console.log(text.charCodeAt(1)); // 57271
複製代碼

漢字「𠮷」是經過代理對錶示的字符,所以在長度上會被斷定爲 2,而且經過 charCodeAt 得到的兩個編碼單元都不表示任何可打印的字符。網絡

codePointAt() 方法

在 ES6 中增長了徹底支持 UTF-16 的 codePointAt 方法。不過這個方法的參數時 編碼單位的位置,而非字符的位置。而且可以返回指定位置對應的碼位。app

const text = '𠮷a';

console.log(text.codePointAt(0)); // 134071,這個整數即字符 𠮷 的碼位
console.log(text.codePointAt(1)); // 57271
console.log(text.codePointAt(2)); // 97,𠮷 是非 BMP 字符,所以佔兩個編碼單位,要查看 a 的碼位就須要傳入 2
複製代碼

用這個方法就能夠判斷字符是不是非 BMP 字符了。函數

function is32Bit(c) {
    return c.codePointAt(0) > 0xFFFF;
}

console.log(is32Bit('𠮷')); // true
console.log(is32Bit('a')); // false
複製代碼

解讀非 BMP 字符

'\uD842\uDFB7'; // 𠮷

'\u20BB7'; // ₻7
複製代碼

對於超出 0xFFFF 的字符,JavaScript 會理解爲 0x20BB0x7 兩個字符,所以會是 ₻7

而在 ES6 中,將碼位用 {} 進行包裹,就能正確解讀出非 BMP 字符。

'\u{20BB7}'; // 𠮷
複製代碼

String.fromCodePoint() 方法

使用 codePointAt() 方法得到的碼位,可使用 String.fromCodePoint() 進行字符生成。

console.log(String.fromCodePoint(134071)); // "𠮷"
複製代碼

當傳入 BMP 字符的碼位時,輸出結果與 String.fromCharCode() 一致,只有當傳入非 BMP 字符的碼位時,結果纔會不一樣。

normalize() 方法

在某些時候,兩個不同的字符會表示一樣的意思而且可以互換,而 JavaScript 並不能準確識別,好比字符 æ 和字符串 ae,雖然嚴格來講兩者並不等價,但在某些場景下兩者是等效的。

爲了解決這個問題,ES6 加入了 normalize() 方法,而且接收一個參數,指明只用如下的方式之一進行標準化:

  • NFC,默認選項,以標準等價方式分解,而後以標準等價方式重組(所謂「標準等價」是指視覺和語義上的等價)
  • NFD,以標準等價方式分解
  • NFKC,以兼容等價方式分解
  • NFKD,以兼容等價方式分解,而後以標準等價方式重組

關於 Unicode 字符標準化的問題與 ES6 關聯較少,要注意的是在開發國際化應用時,在對比字符串以前,能夠先對字符串使用 相同 的標準進行一次標準化,再進行比較。

不過標準化字符串接口 normalize() 也有一些缺陷

  • 沒法識別中文。
  • 沒法識別 3 個及以上的字符的合成。

字符串中子串的識別

在 ES5 以及以前的時間裏,開發者大多使用 indexOf() 方法來檢測字符串中的子字符串。ES6 中提供了 3 個相似的方法來達到相同的效果。

  • includes() - 檢測到指定的文本則返回 true,不然 false
  • startsWith() - 在字符串開頭檢測到指定的文本返回 true,不然 false
  • endsWith() - 在字符串結尾檢測到指定的文本返回 true,不然 false

這三個接口都有兩個參數,第二個參數是可選的,用於指定一個開始位置的索引。

  • 若是指定了第二個參數 nincludes()startsWith() 的匹配範圍是從 n 到字符串結尾,不然從頭開始。
  • 若是指定了第二個參數 nendsWith() 的匹配範圍是前 n 個字符。
const msg = 'Hello';

console.log(msg.includes('ll')); // true
console.log(msg.startsWith('H'); // true
console.log(msg.endsWith('l', 3); // true
複製代碼

若是往 includes()startsWith()endsWith() 傳入一個正則表達式會報錯。對 indexOf()lastIndexOf() 傳入正則表達式,它們會將正則表達式轉爲字符串,而後再進行匹配。

repeat() 方法

返回對當前字符串重複指定次數的新字符串。

const str = 'oop';

console.log(str.repeat(3)); // 'oopoopoop'
複製代碼

模板字面量

基礎語法

模板字面量的基礎語法就是用反撇號代替字符串的單引號或者雙引號。

const str = `Hello World`;
複製代碼

在模板字符串中,反撇號須要使用反斜槓轉義,而單引號與雙引號不須要轉義。

多行字符串

在模板字符串中能夠直接對字符串換行,不過要注意,模板字符串中的每個空格都會被視爲字符串的一部分,所以使用模板字符串輸入多行字符串時要注意字符串中的空格。

字符串佔位符

字符串佔位符能夠將任何合法的 JavaScript 表達式嵌入到字符串中,而且做爲字符串的一部分輸出到結果。

字符串佔位符的語法是 ${},中間能夠是變量、運算式、函數調用等,若是嵌入的是對象等結果非字符串的內容,會採用 JavaScript 默認的規則將其轉換爲字符串(如對象是調用其 toString() 方法)。由於模板字面量自己也是 JavaScript 表達式,所以也能夠進行嵌套

const a = 3;
const b = 2;

console.log(`a * b = ${a * b}`); // 'a * b = 6'
複製代碼

只有當 $ 後立馬接 { 纔會被判斷爲字符串佔位符,不然只是字符 $

標籤模板

字符串模板能夠跟在一個函數名後,該函數將會被調用來處理這個字符串模板,這就是標籤模板功能。

alert`apple`;

// 等同於
alert('apple');
複製代碼

可是當字符串模板中有其餘的變量或者佔位符時,參數會被處理。

tag`Hello ${man}!`;

// 等同於
tag(['Hello ', '!'], man);

function tag(strArr, ...values) {
    ...
}
複製代碼

標籤模板的輸出結果就取決於函數 tag 的輸出結果。

在模板字面量中使用原始值

若是須要查看模板字面量轉義前的原始值,可使用 String.raw 標籤

const message1 = `Multiline\nstring`;
const message2 = String.raw`Multiline\nstring`;

console.log(message1); // Multiline
                       // string
console.log(message2); // Multiline\\nstring
複製代碼

參考資料

相關文章
相關標籤/搜索