title: ES6-字符串和正則表達(dá)式
date: 2018-01-30 22:15:59
tags: es6
前言
入行這么久了氢伟,前端學(xué)習(xí)的成本感覺越來越高了,不會(huì)的東西一茬接一茬或粮,在學(xué)校太忽視它导饲,學(xué)的半吊子,現(xiàn)在要努力趕上才行,杭州的天氣變冷了帜消,我也想回家了棠枉,堅(jiān)持,哎嘿泡挺,再上半個(gè)月班就要放假了開心辈讶。(這是從我自己博客移植過來的)
我的博客地址 :http://www.aymfx.cn/,歡迎訪問
引子
這張理解起來比較費(fèi)勁娄猫,慢慢看贱除,慢慢練,天氣比較冷啊,手敲這些好費(fèi)勁
utf-16碼位(基本多文種平面)到輔助平面字符的擴(kuò)展
在ES6之前媳溺, JS 的字符串以 16 位字符編碼(UTF-16)為基礎(chǔ)月幌。每個(gè) 16 位序列(相當(dāng)于2個(gè)字節(jié))是一個(gè)編碼單元(code unit),可簡(jiǎn)稱為碼元悬蔽,用于表示一個(gè)字符扯躺。字符串所有的屬性與方法(如length屬性與charAt() 方法等)都是基于16位序列
最常用的Unicode字符使用16位序列編碼字符,屬于“基本多語種平面”(Basic Multilingual Plane BMP)蝎困,也稱為“零斷面”(plan 0)录语, 是Unicode中的一個(gè)編碼區(qū)段,編碼介于\u0000~\uFFFF之間禾乘。超過這個(gè)范圍的碼位則要?dú)w屬于某個(gè)輔助平面或稱為擴(kuò)展平面(supplementary plane)澎埠,其中的碼位僅用16位就無法表示了 為此,UTF-16引入了代理對(duì)(surrogate pairs)始藕,規(guī)定用兩個(gè)16位編碼來表示一個(gè)碼位蒲稳。這意味著,字符串里的字符有兩種:一種由一個(gè)碼元(共 16 位)來表示BMP字符伍派,另一種用兩個(gè)碼元(共 32 位)來表示輔助平面字符
let text = '?'
console.log(text.length); //2
console.log(/^.$/.test(text)); //false
console.log(text.charAt(0)); //?
console.log(text.charAt(1)); //?
console.log(text.charCodeAt(0)); //55362
console.log(text.charCodeAt(1)); //57271
這個(gè)字?(jí)其實(shí)就是一個(gè)兩個(gè)16位字符組成的字,基于16位字符串的屬性與方法便失效了
codePointAt() 只接受編碼單元的位置而非字符位置作為參數(shù),返回給定位置對(duì)應(yīng)的碼位
let text = 'a?'
console.log(text.charCodeAt(0)); //55362
console.log(text.charCodeAt(1)); //57271
console.log(text.charCodeAt(2)); //57271
console.log(text.codePointAt(0)); //134071
console.log(text.codePointAt(1)); //57271
console.log(text.codePointAt(2)); //57271
通過這個(gè)方法我們可以檢測(cè)字符是不是32位的
function is32Bit(char){
return char.codePointAt(0) > 0xffff;
}
console.log(is32Bit('?')); //ture
console.log(is32Bit('a')); //false
String.fromCodePoint()通過碼位獲得對(duì)應(yīng)字符
console.log(String.fromCodePoint(134071)); //?
normalize()
許多歐洲語言有語調(diào)符號(hào)和重音符號(hào)江耀。為了表示它們,Unicode提供了兩種方法诉植。一種是直接提供帶重音符號(hào)的字符决记,比如ǒ(\u01D1)。另一種是提供合成符號(hào)(combining character)倍踪,即原字符與重音符號(hào)的合成系宫,兩個(gè)字符合成一個(gè)字符,比如O(\u004F)和ˇ(\u030C)合成ǒ(\u004F\u030C)建车。
這兩種表示方法扩借,在視覺和語義上都等價(jià),但是JavaScript不能識(shí)別缤至。
'\u01D1'==='\u004F\u030C' //false
'\u01D1'.length // 1
'\u004F\u030C'.length // 2
'\u01D1'.normalize() === '\u004F\u030C'.normalize() // true
- NFC潮罪,默認(rèn)參數(shù)康谆,表示“標(biāo)準(zhǔn)等價(jià)合成”(Normalization Form Canonical Composition),返回多個(gè)簡(jiǎn)單字符的合成字符嫉到。所謂“標(biāo)準(zhǔn)等價(jià)”指的是視覺和語義上的等價(jià)沃暗。
- NFD,表示“標(biāo)準(zhǔn)等價(jià)分解”(Normalization Form Canonical Decomposition)何恶,即在標(biāo)準(zhǔn)等價(jià)的前提下孽锥,返回合成字符分解的多個(gè)簡(jiǎn)單字符。
- NFKC细层,表示“兼容等價(jià)合成”(Normalization Form Compatibility Composition)惜辑,返回合成字符。所謂“兼容等價(jià)”指的是語義上存在等價(jià)疫赎,但視覺上不等價(jià)盛撑,比如“囍”和“喜喜”。(這只是用來舉例捧搞,normalize方法不能識(shí)別中文抵卫。)
- NFKD,表示“兼容等價(jià)分解”(Normalization Form Compatibility Decomposition)胎撇,即在兼容等價(jià)的前提下介粘,返回合成字符分解的多個(gè)簡(jiǎn)單字符
正則表達(dá)式u修飾符
let text = '?'
console.log(/^.$/.test(text)); //false
console.log(/^.$/u.test(text)); //true
計(jì)算碼位的數(shù)量
function codePointLength(text){
let result = text.match(/[\s\S]/gu);
return result ? result.length : 0;
}
console.log(codePointLength("123a")); //4
console.log(codePointLength("?a")); //2
console.log(codePointLength("?哦")); //2
//emmmmm。運(yùn)行效率蠻低创坞,聽說有更簡(jiǎn)單的受葛,后面演示
字符串中子串的識(shí)別
includes(x,y)檢測(cè)指定字符串返回boolean值题涨,第二參數(shù)是開始位置(0開始數(shù))
let text = "adsdasdasgsgwefsfs";
let subtext = 'asd';
console.log(text.includes(subtext,4)) //true
console.log(text.includes(subtext)) //true
console.log(text.includes('sdadasda')) //false
startsWith(x,y) 和 endsWith(x,y) 檢測(cè)字符串開頭和結(jié)尾的是否與子串相匹配,第二參數(shù)是開始位置(0開始數(shù))
let text = "adsdasdasgsgwefsfs";
let subtext1 = 'ads';
let subtext2 = 'sfs';
console.log(text.startsWith('asd',4)) //true
console.log(text.startsWith(subtext1)) //true
console.log(text.startsWith('sdadasda')) //false
console.log(text.endsWith('gsgwefsfs',18)) //true 以最后一個(gè)字母的位置為準(zhǔn)
console.log(text.endsWith(subtext2)) //true
console.log(text.endsWith('sdadasda')) //false
repeat() 接受一個(gè)number,即將字符重復(fù)的次數(shù)
console.log('x'.repeat(6)); // xxxxxx
console.log('ly'.repeat(3)); //lylyly
console.log('愛'.repeat(2)); //愛愛
正則的語法變更 (蠻頭疼的,正則還是暈乎乎的)
正則表達(dá)式y(tǒng)修飾符
除了u 修飾符闰渔,ES6還為正則表達(dá)式添加了 y 修飾符蒂阱,叫做“粘連”修飾符了嚎。y 修飾符的作用與 g 修飾符類似赘风,也是全局匹配夹囚,后一次匹配都從上一次匹配成功的下一個(gè)位置開始。不同之處在于邀窃,g 修飾符只要剩余位置中存在匹配就可荸哟,而 y 修飾符確保匹配必須從剩余的第一個(gè)位置開始,這也就是“粘連”的含義瞬捕,當(dāng)為匹配到時(shí)鞍历,將會(huì)返回空,lastIndex將會(huì)置為0
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
console.log(r1.exec(s)) //["aaa", index: 0, input: "aaa_aa_a"] console.log(r2.exec(s)) //["aaa", index: 0, input: "aaa_aa_a"]
console.log(r1.lastIndex) //3
console.log(r2.lastIndex) //3
console.log(r1.exec(s)) //["aa", index: 4, input: "aaa_aa_a"]
console.log(r2.exec(s)) //null
console.log(r1.lastIndex) //6
console.log(r2.lastIndex) //0
console.log(r1.exec(s)) //["a", index: 7, input: "aaa_aa_a"]
console.log(r2.exec(s)) //["aaa", index: 0, input: "aaa_aa_a"] console.log(r1.lastIndex) //8
console.log(r2.lastIndex) //3
檢測(cè)y修飾符是否存在
let pattern = /hello\d/y;
console.log(pattern.sticky) //true 谷歌瀏覽器下
正則表達(dá)式的復(fù)制
es5 如下復(fù)制
var re1 = /ab/i
re2 = new RegExp(re1);
console.log(re1.construct === re2.construct) //true
es6新增了可以添加傳修飾符
var re1 = /ab/i
re2 = new RegExp(re1,'g');
console.log(re1.toString()) ///ab/i
console.log(re2.toString()) ///ab/g
flags屬性
source獲取正則表達(dá)式文本 flags獲取其修飾符
let re = /ab/gi;
console.log(re.source); //ab
console.log(re.flags); //gi
模板字面量
JS 的字符串相對(duì)其他語言來說功能總是有限的肪虎,事實(shí)上劣砍,ES5中一直缺乏許多特性,如多行字符串扇救、字符串格式化刑枝、HTML轉(zhuǎn)義等。ES6通過模板字面量的方式進(jìn)行了填補(bǔ)迅腔,模板字面量試著跳出JS已有的字符串體系装畅,通過一些全新的方法來解決類似的問題
反引號(hào)(``)
const name = 'ly';
let message = `${name},is a man` //ly,is a man
console.log(message);
//${} 可以寫變量 名叫字符串占位符
console.log(`\`hh\``); //`hh`
//es5 實(shí)現(xiàn)多行文本
var message = " ly \n \
love you"
console.log(message);
//es6
var message = ` ly
love you`
console.log(message); // ly
// love you
字符串占位符 ${javascript表達(dá)式}
let count = 15,
price = .5,
message = `${count} items cost $${(count*price).toFixed(1)}`;
console.log(message); //15 items cost $7.5
標(biāo)簽?zāi)0?/h4>
標(biāo)簽?zāi)0迤鋵?shí)不是模板,而是函數(shù)調(diào)用的一種特殊形式沧烈÷有郑“標(biāo)簽”指的是函數(shù),緊跟在后面的模板字符串就是它的參數(shù)
var a = 5;
var b = 10;
tag `Hello ${a+b} world ${a*b}`;
//這個(gè)標(biāo)識(shí)名tag,它是一個(gè)函數(shù)锌雀。整個(gè)表達(dá)式的返回值蚂夕,就是tag函數(shù)處理模板字符串之后的返回值。函數(shù)tag會(huì)依次接收到多個(gè)參數(shù)腋逆。
tag函數(shù)的第一個(gè)參數(shù)是一個(gè)數(shù)組双抽,該數(shù)組的成員時(shí)模板字符串中那些沒有變量替換的部分,也就是說闲礼,變量替換只發(fā)生在數(shù)組的第一個(gè)成員和第二個(gè)成員之間牍汹,以此類推铐维。tag函數(shù)的其他參數(shù)都是模板字符串各個(gè)變量被替換后的值,由于本例中慎菲,模板字符串含有兩個(gè)變量嫁蛇,因此tag會(huì)接收到value1和value2兩個(gè)參數(shù)。
tag函數(shù)所有參數(shù)的實(shí)際值如下:
——第一個(gè)參數(shù):['Hello ',' world ','']
——第二個(gè)參數(shù):15
——第三個(gè)參數(shù):50
也就是說tag函數(shù)實(shí)際上是以下面的形式調(diào)用的
tag(['Hello ',' world ',''],15,50);
我們可以按照需要編寫tag 函數(shù)的代碼露该。
var count = 5;
var price = 10;
function tag(s,v1,v2,v3){
console.log(s[0]);
console.log(s[1]);
console.log(s[2]);
console.log(s);
console.log(v1);
console.log(v2);
return 'ok'
}
tag`q${count} items cost $${(count*price).toFixed(1)}.`;
//VM173:5
//VM173:6 items cost $
//VM173:7 .
//VM173:8 5
//VM173:9 50.0
//ok
標(biāo)簽函數(shù)的常用形式
function tag(literals,...substitutions){
//literals 值得是被${}隔開的字符
//substitutions睬棚,有幾個(gè)${}就有幾個(gè)這個(gè)
}
利用 literals.length-1 === substitutions.length,拼接字符串
function passthru(literals,...values){
var output ="";
for(var index = 0;index<values.length;index++){
output = literals[index]+values[index];
}
output+=literals[index];
return output;
}
let count = 15,
price = .5,
message = passthru`${count} items cost $${(count*price).toFixed(1)}`;
console.log(message); //15 items cost $7.5
what?這樣做的意義是啥?
emmm,過濾html字符串,還有一些轉(zhuǎn)義字符的過濾
function SaferHTML(templateData){
var s = templateData[0];
var i;
for(i = 1;i<arguments.length;i++){
var arg = String(arguments[i]);
//sender里面可能有特殊字符解幼,進(jìn)行轉(zhuǎn)義
s += arg.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">");
s += templateData[i];
}
console.log(i);//2抑党,表示這個(gè)循環(huán)只執(zhí)行了一次,因?yàn)閠emplateData[0]="<p>",arguments這個(gè)數(shù)組只有${sender}這個(gè)元素撵摆,后面一長(zhǎng)串字符都是templateData[2];
return s;
}
var sender = '<script>alert("abc")</script>';
var message = SaferHTML`<p>${sender} has sent you a message.</p>`;
console.log(message);
在模板字面量中使用原始值
使用內(nèi)建對(duì)象String.raw訪問
let ms1 = `ly\n love you`
let ms2 = String.raw`ly\n love you`
console.log(ms1); //ly
//love you
console.log(ms2); // ly\n love you
標(biāo)簽?zāi)0迤鋵?shí)不是模板,而是函數(shù)調(diào)用的一種特殊形式沧烈÷有郑“標(biāo)簽”指的是函數(shù),緊跟在后面的模板字符串就是它的參數(shù)
var a = 5;
var b = 10;
tag `Hello ${a+b} world ${a*b}`;
//這個(gè)標(biāo)識(shí)名tag,它是一個(gè)函數(shù)锌雀。整個(gè)表達(dá)式的返回值蚂夕,就是tag函數(shù)處理模板字符串之后的返回值。函數(shù)tag會(huì)依次接收到多個(gè)參數(shù)腋逆。
tag函數(shù)的第一個(gè)參數(shù)是一個(gè)數(shù)組双抽,該數(shù)組的成員時(shí)模板字符串中那些沒有變量替換的部分,也就是說闲礼,變量替換只發(fā)生在數(shù)組的第一個(gè)成員和第二個(gè)成員之間牍汹,以此類推铐维。tag函數(shù)的其他參數(shù)都是模板字符串各個(gè)變量被替換后的值,由于本例中慎菲,模板字符串含有兩個(gè)變量嫁蛇,因此tag會(huì)接收到value1和value2兩個(gè)參數(shù)。
tag函數(shù)所有參數(shù)的實(shí)際值如下:
——第一個(gè)參數(shù):['Hello ',' world ','']
——第二個(gè)參數(shù):15
——第三個(gè)參數(shù):50
也就是說tag函數(shù)實(shí)際上是以下面的形式調(diào)用的
tag(['Hello ',' world ',''],15,50);
我們可以按照需要編寫tag 函數(shù)的代碼露该。
var count = 5;
var price = 10;
function tag(s,v1,v2,v3){
console.log(s[0]);
console.log(s[1]);
console.log(s[2]);
console.log(s);
console.log(v1);
console.log(v2);
return 'ok'
}
tag`q${count} items cost $${(count*price).toFixed(1)}.`;
//VM173:5
//VM173:6 items cost $
//VM173:7 .
//VM173:8 5
//VM173:9 50.0
//ok
標(biāo)簽函數(shù)的常用形式
function tag(literals,...substitutions){
//literals 值得是被${}隔開的字符
//substitutions睬棚,有幾個(gè)${}就有幾個(gè)這個(gè)
}
利用 literals.length-1 === substitutions.length,拼接字符串
function passthru(literals,...values){
var output ="";
for(var index = 0;index<values.length;index++){
output = literals[index]+values[index];
}
output+=literals[index];
return output;
}
let count = 15,
price = .5,
message = passthru`${count} items cost $${(count*price).toFixed(1)}`;
console.log(message); //15 items cost $7.5
what?這樣做的意義是啥?
emmm,過濾html字符串,還有一些轉(zhuǎn)義字符的過濾
function SaferHTML(templateData){
var s = templateData[0];
var i;
for(i = 1;i<arguments.length;i++){
var arg = String(arguments[i]);
//sender里面可能有特殊字符解幼,進(jìn)行轉(zhuǎn)義
s += arg.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">");
s += templateData[i];
}
console.log(i);//2抑党,表示這個(gè)循環(huán)只執(zhí)行了一次,因?yàn)閠emplateData[0]="<p>",arguments這個(gè)數(shù)組只有${sender}這個(gè)元素撵摆,后面一長(zhǎng)串字符都是templateData[2];
return s;
}
var sender = '<script>alert("abc")</script>';
var message = SaferHTML`<p>${sender} has sent you a message.</p>`;
console.log(message);
使用內(nèi)建對(duì)象String.raw訪問
let ms1 = `ly\n love you`
let ms2 = String.raw`ly\n love you`
console.log(ms1); //ly
//love you
console.log(ms2); // ly\n love you