本文知識點主要整理自《深刻理解 ES6(Understanding ECMAScript 6)》中文版實體書的內容,部分地方會加上本身的理解,同時書中敘述比較模糊的部分參考了阮一峯老師的《ECMAScript 6 入門》與網絡上其餘大佬們的博客、問答,篇幅有限沒法一一列出,在此表示感謝。javascript
Unicode 是計算機領域內的一項業界標準,它對世界上大部分的文字系統進行了整理、編碼,目的是爲世界上每個字符提供全球惟一的標識符。Unicode 有兩個步驟,一是給字符規定一個惟一對應的數字;二是將字符對應的數字保存在計算機中。html
Unicode 對字符的惟一標識被稱爲碼位(code point)。JavaScript 的字符串一直是基於 UTF-16 進行構建,每 16 位的序列視爲一個編碼單元(code unit),表明一個字符。而且 length
、charAt()
等字符串的屬性與方法都是基於這種編碼單元構造的。java
在 UTF-16 中,字符編碼空間由 U+0000
到 U+10FFFF
一共 1112064
個碼位。同時編碼空間一共分爲 17 個平面(plane),每個平面包含 U+xx0000
到 U+xxFFFF
一共 65536 個碼位。而第一個平面(U+0000
到 U+FFFF
)被稱爲 基本多文種平面(Basic Multilingual Plane,簡稱 BMP)。其餘平面被稱爲 輔助平面。git
在早期 16 位足以包含任何字符,但隨着計算機的發展,更多語言與符號的加入,16 位已經不夠用,所以 UTF-16 加入了代理對(surrogate pair),其規定用兩個 16 位編碼單元表示一個碼位。es6
所以,UTF-16 中有兩種字符github
在 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
得到的兩個編碼單元都不表示任何可打印的字符。網絡
在 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
複製代碼
'\uD842\uDFB7'; // 𠮷
'\u20BB7'; // ₻7
複製代碼
對於超出 0xFFFF
的字符,JavaScript 會理解爲 0x20BB
和 0x7
兩個字符,所以會是 ₻7
。
而在 ES6 中,將碼位用 {}
進行包裹,就能正確解讀出非 BMP 字符。
'\u{20BB7}'; // 𠮷
複製代碼
使用 codePointAt()
方法得到的碼位,可使用 String.fromCodePoint()
進行字符生成。
console.log(String.fromCodePoint(134071)); // "𠮷"
複製代碼
當傳入 BMP 字符的碼位時,輸出結果與 String.fromCharCode()
一致,只有當傳入非 BMP 字符的碼位時,結果纔會不一樣。
在某些時候,兩個不同的字符會表示一樣的意思而且可以互換,而 JavaScript 並不能準確識別,好比字符 æ
和字符串 ae
,雖然嚴格來講兩者並不等價,但在某些場景下兩者是等效的。
爲了解決這個問題,ES6 加入了 normalize()
方法,而且接收一個參數,指明只用如下的方式之一進行標準化:
關於 Unicode 字符標準化的問題與 ES6 關聯較少,要注意的是在開發國際化應用時,在對比字符串以前,能夠先對字符串使用 相同 的標準進行一次標準化,再進行比較。
不過標準化字符串接口 normalize()
也有一些缺陷
在 ES5 以及以前的時間裏,開發者大多使用 indexOf()
方法來檢測字符串中的子字符串。ES6 中提供了 3 個相似的方法來達到相同的效果。
includes()
- 檢測到指定的文本則返回 true
,不然 false
。startsWith()
- 在字符串開頭檢測到指定的文本返回 true
,不然 false
。endsWith()
- 在字符串結尾檢測到指定的文本返回 true
,不然 false
。這三個接口都有兩個參數,第二個參數是可選的,用於指定一個開始位置的索引。
n
,includes()
和 startsWith()
的匹配範圍是從 n
到字符串結尾,不然從頭開始。n
,endsWith()
的匹配範圍是前 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()
傳入正則表達式,它們會將正則表達式轉爲字符串,而後再進行匹配。
返回對當前字符串重複指定次數的新字符串。
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
複製代碼