RegExp 構(gòu)造函數(shù)
在 ES5 中,RegExp構(gòu)造函數(shù)的參數(shù)有兩種情況。
第一種情況是,參數(shù)是字符串,這時(shí)第二個(gè)參數(shù)表示正則表達(dá)式的修飾符(flag)。
var regex = new RegExp('xyz', 'i');
// 等價(jià)于
var regex = /xyz/i;
第二種情況是,參數(shù)是一個(gè)正則表示式,這時(shí)會(huì)返回一個(gè)原有正則表達(dá)式的拷貝。
var regex = new RegExp(/xyz/i);
// 等價(jià)于
var regex = /xyz/i;
但是,ES5 不允許此時(shí)使用第二個(gè)參數(shù)添加修飾符,否則會(huì)報(bào)錯(cuò)。
var regex = new RegExp(/xyz/, 'i');
// Uncaught TypeError: Cannot supply flags when constructing one RegExp from another
ES6 改變了這種行為。如果RegExp構(gòu)造函數(shù)第一個(gè)參數(shù)是一個(gè)正則對(duì)象,那么可以使用第二個(gè)參數(shù)指定修飾符。而且,返回的正則表達(dá)式會(huì)忽略原有的正則表達(dá)式的修飾符,只使用新指定的修飾符。
new RegExp(/abc/ig, 'i').flags
// "i"
上面代碼中,原有正則對(duì)象的修飾符是ig,它會(huì)被第二個(gè)參數(shù)i覆蓋。
字符串的正則方法
字符串對(duì)象共有 4 個(gè)方法,可以使用正則表達(dá)式:match()、replace()、search()和split()。
ES6 將這 4 個(gè)方法,在語(yǔ)言內(nèi)部全部調(diào)用RegExp的實(shí)例方法,從而做到所有與正則相關(guān)的方法,全都定義在RegExp對(duì)象上。
String.prototype.match 調(diào)用 RegExp.prototype[Symbol.match]
String.prototype.replace 調(diào)用 RegExp.prototype[Symbol.replace]
String.prototype.search 調(diào)用 RegExp.prototype[Symbol.search]
String.prototype.split 調(diào)用 RegExp.prototype[Symbol.split]
u 修飾符
ES6 對(duì)正則表達(dá)式添加了u修飾符,含義為“Unicode 模式”,用來(lái)正確處理大于\uFFFF的 Unicode 字符。也就是說(shuō),會(huì)正確處理四個(gè)字節(jié)的 UTF-16 編碼。
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
上面代碼中,\uD83D\uDC2A是一個(gè)四個(gè)字節(jié)的 UTF-16 編碼,代表一個(gè)字符。但是,ES5 不支持四個(gè)字節(jié)的 UTF-16 編碼,會(huì)將其識(shí)別為兩個(gè)字符,導(dǎo)致第二行代碼結(jié)果為true。加了u修飾符以后,ES6 就會(huì)識(shí)別其為一個(gè)字符,所以第一行代碼結(jié)果為false。
一旦加上u修飾符號(hào),就會(huì)修改下面這些正則表達(dá)式的行為。
(1)點(diǎn)字符
點(diǎn)(.)字符在正則表達(dá)式中,含義是除了換行符以外的任意單個(gè)字符。對(duì)于碼點(diǎn)大于0xFFFF的 Unicode 字符,點(diǎn)字符不能識(shí)別,必須加上u修飾符。
var s = '??';
/^.$/.test(s) // false
/^.$/u.test(s) // true
上面代碼表示,如果不添加u修飾符,正則表達(dá)式就會(huì)認(rèn)為字符串為兩個(gè)字符,從而匹配失敗。
(2)Unicode 字符表示法
ES6 新增了使用大括號(hào)表示 Unicode 字符,這種表示法在正則表達(dá)式中必須加上u修飾符,才能識(shí)別當(dāng)中的大括號(hào),否則會(huì)被解讀為量詞。
/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('??') // true
上面代碼表示,如果不加u修飾符,正則表達(dá)式無(wú)法識(shí)別\u{61}這種表示法,只會(huì)認(rèn)為這匹配 61 個(gè)連續(xù)的u。
(3)量詞
使用u修飾符后,所有量詞都會(huì)正確識(shí)別碼點(diǎn)大于0xFFFF的 Unicode 字符。
/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true
/??{2}/.test('????') // false
/??{2}/u.test('????') // true
(4)預(yù)定義模式
u修飾符也影響到預(yù)定義模式,能否正確識(shí)別碼點(diǎn)大于0xFFFF的 Unicode 字符。
/^\S$/.test('??') // false
/^\S$/u.test('??') // true
上面代碼的\S是預(yù)定義模式,匹配所有非空白字符。只有加了u修飾符,它才能正確匹配碼點(diǎn)大于0xFFFF的 Unicode 字符。
利用這一點(diǎn),可以寫(xiě)出一個(gè)正確返回字符串長(zhǎng)度的函數(shù)。(可以用來(lái)做字符長(zhǎng)度驗(yàn)證)
function codePointLength(text) {
var result = text.match(/[\s\S]/gu);
return result ? result.length : 0;
}
var s = '????';
s.length // 4
codePointLength(s) // 2
(5)i 修飾符
有些 Unicode 字符的編碼不同,但是字型很相近,比如,\u004B與\u212A都是大寫(xiě)的K。
/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true
上面代碼中,不加u修飾符,就無(wú)法識(shí)別非規(guī)范的K字符。
(6)轉(zhuǎn)義
沒(méi)有u修飾符的情況下,正則中沒(méi)有定義的轉(zhuǎn)義(如逗號(hào)的轉(zhuǎn)義,)無(wú)效,而在u模式會(huì)報(bào)錯(cuò)。
/\,/ // /\,/
/\,/u // 報(bào)錯(cuò)
上面代碼中,沒(méi)有u修飾符時(shí),逗號(hào)前面的反斜杠是無(wú)效的,加了u修飾符就報(bào)錯(cuò)。