ES6 增強了對 Unicode 的支持,容許採用\uxxxx
形式表示一個字符,其中xxxx
表示字符的 Unicode 碼點。javascript
限於碼點在\u0000
~\uFFFF
之間的字符。超出這個範圍的字符,必須用兩個雙字節的形式表示。java
直接在\u
後面跟上超過0xFFFF
的數值會理解錯誤。git
改進方案,只要將碼點放入大括號,就能正確解讀該字符github
"\u{20BB7}"
// "𠮷
複製代碼
'z' === 'z' // true
'\z' === 'z' // true 122
'\172' === 'z' // true 1*8*8 + 7*8 +2 = 122 // 對應下面的\ddd模式
'\x7A' === 'z' // true 7*16 + 10 // 對應下面的\xhh模式
'\u007A' === 'z' // true // Unicode 表示法
'\u{7A}' === 'z' // true // Unicode 改進後表示法
複製代碼
傳統的for
循環沒法識別大於0xFFFF
的碼點,而for...of
能夠。正則表達式
for (let i of text) {
console.log(i);
}
// "𠮷"
複製代碼
JavaScript 字符串容許直接輸入字符,以及輸入字符的轉義形式。能夠直接在字符串裏面輸入這個漢字,也能夠輸入它的轉義形式\u4e2d
,二者是等價的。json
'中' === '\u4e2d' // true
複製代碼
JavaScript 規定有5個字符,不能在字符串裏面直接使用,只能使用轉義形式。數組
U+005C:反斜槓(reverse solidus)markdown
U+000D:回車(carriage return)函數
U+2028:行分隔符(line separator)oop
U+2029:段分隔符(paragraph separator)
U+000A:換行符(line feed)
爲消除JSON JSON.parse
解析行分隔符與段分隔符的異常,ES2019 容許 JavaScript 字符串直接輸入 U+2028(行分隔符)和 U+2029(段分隔符)。
注意,模板字符串如今就容許直接輸入這兩個字符。另外,正則表達式依然不容許直接輸入這兩個字符,這是沒有問題的,由於 JSON 原本就不容許直接包含正則表達式。
JSON 數據必須是 UTF-8 編碼。可是,如今的JSON.stringify()
方法有可能返回不符合 UTF-8 標準的字符串。
爲了確保返回的是合法的 UTF-8 字符,ES2019 改變了JSON.stringify()
的行爲。若是遇到0xD800
到0xDFFF
之間的單個碼點,或者不存在的配對形式,它會返回轉義字符串。
例如:僅最後的語句返回 ""𝌆""
JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""
JSON.stringify('\uD834\uDF06')
複製代碼
模板字符串(template string)是加強版的字符串,用反引號(`)標識。它能夠看成普通字符串使用,也能夠用來定義多行字符串,或者在字符串中嵌入變量。
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is not legal.`
console.log(`string text line 1 string text line 2`);
// 字符串中嵌入變量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
複製代碼
${}
嵌入變量。${}
大括號內部能夠放入任意的 JavaScript 表達式,能夠進行運算,以及引用對象屬性。${}
大括號內部還能調用函數。${}
大括號內部是一個字符串,將會原樣輸出。模板字符串能夠緊跟在一個函數名後面,該函數將被調用來處理這個模板字符串。這被稱爲「標籤模板」功能(tagged template)。標籤模板其實不是模板,而是函數調用的一種特殊形式。「標籤」指的就是函數,緊跟在後面的模板字符串就是它的參數。
模板字符串默認會將字符串轉義(\u
和\x
等),致使沒法嵌入其餘語言。
ES2018 放鬆了對標籤模板裏面的字符串轉義的限制。若是遇到不合法的字符串轉義,就返回undefined
,而不是報錯,而且從raw
屬性上面能夠獲得原始字符串。
對字符串轉義的放鬆,只在標籤模板解析字符串時生效,不是標籤模板的場合,依然會報錯。
let bad = `bad escape sequence: \unicode`; // 報錯
複製代碼
ES5 提供String.fromCharCode()
方法,用於從 Unicode 碼點返回對應字符,可是這個方法不能識別碼點大於0xFFFF
的字符。ES6 提供了String.fromCodePoint()
方法,能夠識別大於0xFFFF
的字符,彌補了String.fromCharCode()
方法的不足。
String.fromCharCode(0x20BB7)
// "ஷ"
String.fromCodePoint(0x20BB7)
// "𠮷"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true
複製代碼
String.fromCodePoint()
方法與下面的codePointAt()
相反。
JavaScript 內部,字符以 UTF-16 的格式儲存,每一個字符固定爲2
個字節。對於那些須要4
個字節儲存的字符(Unicode 碼點大於0xFFFF
的字符),JavaScript 會認爲它們是兩個字符。
var s = "𠮷";
s.length // 2
s.charAt(0) // ''
s.charAt(1) // ''
s.charCodeAt(0) // 55362
s.charCodeAt(1) // 57271
複製代碼
根據以上示例發現,對於4 個字節儲存的字符,ES5提供的charAt
,charCodeAt
沒法返回咱們想要的值。
ES6 提供了codePointAt()
方法,可以正確處理 4 個字節儲存的字符,返回一個字符的碼點。
let s = '𠮷a';
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
複製代碼
可是,codePointAt()
方法的參數,仍然是不正確的。上面代碼中,字符a
在字符串s
的正確位置序號應該是 1,可是必須向codePointAt()
方法傳入 2。
方法一:使用for...of
循環
let s = '𠮷a';
for (let ch of s) {
console.log(ch.codePointAt(0).toString(16));
}
// 20bb7
// 61
複製代碼
方法二:使用擴展運算符(...
)進行展開運算
let arr = [...'𠮷a']; // arr.length === 2
arr.forEach(
ch => console.log(ch.codePointAt(0).toString(16))
);
// 20bb7
// 61
複製代碼
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("𠮷") // true
is32Bit("a") // false
複製代碼
String.raw()
方法返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字符串,每每用於模板字符串的處理方法。
String.raw`Hi\n${2+3}!`
// 實際返回 "Hi\\n5!",顯示的是轉義後的結果 "Hi\n5!"
複製代碼
函數的形式,它的第一個參數,應該是一個具備raw
屬性的對象,且raw
屬性的值應該是一個數組,對應模板字符串解析後的值。
`foo${1 + 2}bar`
// 等同於
String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
複製代碼
String.raw = function (strings, ...values) {
let output = '';
let index;
for (index = 0; index < values.length; index++) {
output += strings.raw[index] + values[index];
}
output += strings.raw[index]
return output;
}
複製代碼
許多歐洲語言有語調符號和重音符號。爲了表示它們,Unicode 提供了兩種方法。
一種是直接提供帶重音符號的字符,好比Ǒ
(\u01D1)。
另外一種是提供合成符號(combining character),即原字符與重音符號的合成,兩個字符合成一個字符,好比O
(\u004F)和ˇ
(\u030C)合成Ǒ
(\u004F\u030C)。
這兩種表示方法,在視覺和語義上都等價,可是 JavaScript 不能識別。以下,長度不一致並且相等判斷爲false
。
'\u01D1'==='\u004F\u030C' //false
'\u01D1'.length // 1
'\u004F\u030C'.length // 2
複製代碼
ES6 提供字符串實例的normalize()
方法,用來將字符的不一樣表示方法統一爲一樣的形式,這稱爲 Unicode 正規化。
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
// true
複製代碼
normalize
方法能夠接受一個參數來指定normalize
的方式,參數的四個可選值以下:
NFC
,默認參數,表示「標準等價合成」(Normalization Form Canonical Composition),返回多個簡單字符的合成字符。所謂「標準等價」指的是視覺和語義上的等價。
NFD
,表示「標準等價分解」(Normalization Form Canonical Decomposition),即在標準等價的前提下,返回合成字符分解的多個簡單字符。
NFKC
,表示「兼容等價合成」(Normalization Form Compatibility Composition),返回合成字符。所謂「兼容等價」指的是語義上存在等價,但視覺上不等價,好比「囍」和「喜喜」。(這只是用來舉例,normalize
方法不能識別中文。)
NFKD
,表示「兼容等價分解」(Normalization Form Compatibility Decomposition),即在兼容等價的前提下,返回合成字符分解的多個簡單字符。
'\u004F\u030C'.normalize('NFC').length // 1
'\u004F\u030C'.normalize('NFD').length // 2
複製代碼
normalize
方法目前不能識別三個或三個以上字符的合成。這種狀況下,仍是隻能使用正則表達式,經過 Unicode 編號區間判斷。
ES5 時代,JavaScript 只有indexOf
方法,能夠用來肯定一個字符串是否包含在另外一個字符串中。
ES6 提供了三種新方法:
includes():返回布爾值,表示是否找到了參數字符串。
startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
複製代碼
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true 針對前n個字符,即'Hello'
s.includes('Hello', 6) // false
複製代碼
上面代碼表示,使用第二個參數n
時,endsWith
的行爲與其餘兩個方法有所不一樣。
endsWith
針對前n
個字符,而includes()
, startsWith()
方法針對從第n
個位置直到字符串結束。
repeat
方法返回一個新字符串,表示將原字符串重複n
次。
repeat
的參數是負數或者Infinity
,會報錯。NaN
等同於 0。'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
'na'.repeat(2.9) // "nana" --參數會被取整
'na'.repeat(Infinity) // RangeError --報錯
'na'.repeat(-1) // RangeError --報錯
'na'.repeat(-0.9) // ""
'na'.repeat(NaN) // ""
'na'.repeat('3') // "nanana" --先轉換成數字
複製代碼
ES2017 引入了字符串補全長度的功能。若是某個字符串不夠指定長度,會在頭部或尾部補全。padStart()
用於頭部補全,padEnd()
用於尾部補全。padStart()
和padEnd()
一共接受兩個參數,第一個參數是字符串補全生效的最大長度,第二個參數是用來補全的字符串。
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'xxx'.padStart(2, 'ab') // 'xxx' --補全不生效,返回原字符串
'xxx'.padEnd(2, 'ab') // 'xxx' --補全不生效,返回原字符串
'abc'.padStart(10, '0123456789') // '0123456abc' --會截去超出位數的補全字符串
'x'.padStart(4) // ' x' --默認使用空格補全長度
複製代碼
數值補全指定位數
'1'.padStart(10, '0') // "0000000001"
複製代碼
提示字符串格式
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
複製代碼
ES2019 對字符串實例新增了trimStart()
和trimEnd()
這兩個方法。它們的行爲與trim()
一致,trimStart()
消除字符串頭部的空格,trimEnd()
消除尾部的空格。
trimLeft()
是trimStart()
的別名,trimRight()
是trimEnd()
的別名(爲了兼容)。