重讀 ES6 — 字符串轴踱、數(shù)值、正則的擴展

從去年開始學(xué)習(xí)及使用 ES6 語法,后得益于項目的推動,到現(xiàn)在已較廣泛的使用 ES6 寫代碼了右蕊。

我們知道,ES6 較之 ES5吮螺,新增特性非常之多饶囚,變化非常大,幾乎像是兩種不同語言鸠补。盡管現(xiàn)在 ES6 滿大街了萝风,但仍有許多有用的特性很少觸及。另外莫鸭,對于已使用的特性闹丐,有的使用頻率高,有的使用頻率比較低被因。

為了在當(dāng)前基礎(chǔ)上更全面一點的了解 ES6,同時對一些較疑難又非常棒的 API 能更深入的理解衫仑,我有個想法就是重新 “畫輪子” 梨与。

雖然個人對這件事有點猶豫,猶豫的點主要因為現(xiàn)在已不乏 ES6 的文檔文狱、資料和問題解答粥鞋;各路牛人一不小心看到本人整理ES6資料,也許因為理解不到位瞄崇、或者無用功而扔磚頭呻粹;最后壕曼,自認(rèn)為寫東西不擅長,是個耗時的苦差事等浊。

但是腮郊,今天還是開始了。

首先筹燕,期望的是收獲對 ES6 更全面的了解轧飞,其間若能領(lǐng)略一些 ES6語言設(shè)計風(fēng)格,窺視 JavaScript 技術(shù)走向撒踪,那也算很好的收獲过咬。另外,新入門的朋友若能因此在 ES6 的學(xué)習(xí)上做一個輕重緩急的劃分制妄,或者收獲些許領(lǐng)悟掸绞,也是極好。

好了耕捞,重新 “畫輪子”集漾,主要基于以下思路:

  • 強調(diào)從 ES5ES6的差異,進行知識迭代
  • 更注重于 API 的設(shè)計角度來分析新增特性
  • 對技術(shù)點進行邊界管理砸脊,將疑難的點先劃在邊界之外具篇,之后再專門突破

縱觀 ES6各種新特性,整理出以下一份清單:

1凌埂、基本類型的擴展
2驱显、新增類型和數(shù)據(jù)結(jié)構(gòu)
3、模塊(Module)
4瞳抓、Promise
5埃疫、異步同步化方案 async/await
6、其他偏語言層面的能力開放

大概以 Promise 為分界孩哑,分類靠前的更基礎(chǔ)栓霜,使用頻率更高,相對來說也比較簡單横蜒;靠后的是更偏向新增特性胳蛮,使用頻率稍低,但它們能量可不小丛晌。而 Promise 本身仅炊,則是一個非常棒的 API。

以下內(nèi)容是上述條目的展開澎蛛,各有詳略抚垄。

基本類型的擴展

很多前端面試,都會問到 JS 的基本類型的理解。

沒錯呆馁,在 ES5 的基礎(chǔ)之上桐经, ES6 對這些基本類型進行了一些擴展,擴展并不是平白新增特性浙滤,而是將 ES5 的一些高頻使用方式等做了封裝阴挣,并 API 化了。

下面依次來看看字符串瓷叫、數(shù)值屯吊、正則數(shù)組摹菠、函數(shù)盒卸、對象以及解構(gòu)賦值這種新的聲明變量的方式。當(dāng)然次氨,正則不屬于基本類型蔽介,這里是借助 “類型的擴展” 這個話題來講的;另外煮寡,函數(shù)和對象的擴展是比較重要的部分虹蓄,會講得稍詳細(xì)些。

字符串的擴展

字符串的擴展幸撕,主要包括:

  • 新增一些方法
  • 增強對一些其他編碼(特別是 Unicode)的識別能力及計算能力
  • 增加模板字符串薇组。

一、新增的方法

新增的方法 includes(), startsWith(), endsWith() 等基本上是對 indexOf() 方法的封裝坐儿。

let str = 'hello world';

//ES6 的 API 直接調(diào)用律胀,語義清晰簡潔
str.endsWith('d');
// => true

//ES5 表達(dá)同樣的意思卻要寫一堆
str.indexOf('d') === str.length - 1;

新增的 repeat() 也是一個簡單明了的方法。如果想將一個字符串重復(fù) copy 若干次貌矿,在 ES5 是大概率得想到用 for 循環(huán)炭菌。

//龐大的循環(huán)語句,重復(fù)字符 `x` 共 n 次
function repeat (n) {
    var str = '';
    for(var i = 0; i < n; i++) {
        str += 'x';
    }
    return str;
}
var str = repeat(10);

//就算靈機一動逛漫,使用其他途徑黑低,有點別扭
var str = new Array(10).join('x');

//ES6 推出一個新方法,封裝這一高頻需求
let str = 'x'.repeat(10);

// 當(dāng)然這個方法的輸入?yún)?shù)有類型等要求酌毡,不在此討論范圍

雖然本質(zhì)上都繞不開循環(huán)克握,但是 repeat() 方法明顯更優(yōu)雅。從語言級別來封裝這一使用場景阔馋,能從更大規(guī)模上節(jié)省不少的代碼信息量玛荞。

二、模板字符串

模板字符串是個非常好的東西呕寝,也是我們非常高頻使用的工具。用 backbone.js 那會,就有很多前端同事下梢,以及從其他語言 “入侵” 的同事抱怨過字符串拼接中的一大堆 + 號和惱人的 " '號了客蹋。

//惱人的 `+` 號和引號
function welcome (name, place) {
    return 'Hello ' + name + ', welcome to ' + place + '!';
}

//ES6 下 瞬間清爽了
function welcome (name, place) {
    return `Hello ${name}, welcome to ${place}!`;
}

JS 代碼中內(nèi)嵌很多模板片段時,模板字符串無論是處理還是維護孽江,都方便很多讶坯。

此外,使用模板字符串可以輕易的實現(xiàn)一個模板庫出來岗屏,此處也不再展開辆琅。

三、編碼格式(如 Unicode)的相關(guān)擴展

最后这刷,擴展了字符串對其他編碼格式的識別和處理能力婉烟,這點目前需求最多(個人感覺)的恐怕的是 i18n 即多語言處理上。這部分的 API 也沒有什么難度暇屋,在使用時在把玩一下即可似袁,平時無需增加認(rèn)知負(fù)擔(dān)。

數(shù)值的擴展

數(shù)值的擴展咐刨,主要的動作是:

  • 將一些 window 下關(guān)于數(shù)值類型的 API 遷移到了更為合理的地方(Number 上)
  • Number 對象上繼續(xù)新增了幾個方法
  • Math 對象上昙衅,則擴展了更多的常規(guī)計算函數(shù)
  • 最后還增加了一些對整型、浮點型數(shù)據(jù)溢出的應(yīng)對方法定鸟。

一而涉、遷移并提純

數(shù)值的擴展,毫無認(rèn)知壓力以及讓人容易理解的是上述的第一個動作:將合適的 API 從錯誤的地方(window 對象中)移到正確的地方(Number 對象)下管理联予。這個如標(biāo)題所說是 "遷移"啼县。

那“提純”怎么說?——"純函數(shù)"躯泰,對的谭羔。如果還不具備純函數(shù)知識的朋友,若看過本人前一篇文章《走向 JavaScript 函數(shù)式編程》 就知道麦向,遷移后的方法瘟裸,變成純函數(shù)了——它不再對參數(shù)(的類型)形成 “副作用” 了。

// 有限的數(shù)值诵竭,就是有限的
Number.isFinite(9999); // => true

//足夠大话告、無限數(shù)、非數(shù)值它就不是有限的
Number.isFinite(Math.pow(99, 9999));  // => false
Number.isFinite(Infinity); // => false
Number.isFinite('999');  // => false

// 對于 NaN 判斷 true
Number.isNaN(NaN); // => true
Number.isNaN(999 / NaN); // => true

// 除 NaN 以外一切都判斷 false
Number.isNaN('NaN'); // => false
Number.isNaN(true) // => false

// 這兩個 API 就是為了得到數(shù)值卵慰,放在 Number 更合理
Number.parseInt();
Number.parseFloat();

移動后的方法 Number.isFinite()沙郭、Number.isNaN() 較之先前也更純粹,它們的參數(shù)不會進行類型自動轉(zhuǎn)化裳朋,是字符串就是字符串病线,是布爾值就是布爾值,不會自作主張轉(zhuǎn)化一下,再去判斷送挑。

而原有的掛載在 window 下的這倆方法的行為讓人捉摸不透绑莺。

// 莫名其妙的對參數(shù)進行了類型轉(zhuǎn)化
isFinite('999'); // => true
isNaN('NaN'); // => true

遷移本身的好處是,逐步減少全局性方法惕耕,使得語言逐步走向模塊化纺裁。本身這點也是 ES6 所倡導(dǎo)的。

二司澎、Number 對象新增計算方法和常量

遷移動作如果是對歷史的修正的話欺缘,下邊就是通過新增更多的元素,來豐富 JavaScript 的數(shù)值計算能力挤安。

// 判斷參數(shù)是否是數(shù)值中的整數(shù)
Number.isInteger(28.0); // => true
Number.isSafeInteger(Infinity) // false

// 新增常量谚殊,都掛在 Number 對象下
Number.EPSILON === 2.220446049250313e-16; // => true
Number.MAX_SAFE_INTEGER === 9007199254740991; // => true
Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER; // => true

Number.isInteger(),Number.isSafeInteger() 也是 “提純” 后的方法,即不會擅自轉(zhuǎn)化參數(shù)類型漱受。

上述常量也非常好理解络凿。它們的添加,給實際編程時減少了很多負(fù)擔(dān)昂羡,因為現(xiàn)在任何時候絮记,再也不用自己寫一個 const MAX_INTEGER = Math.pow(2, 53)了,即拿即用就好了虐先。

三怨愤、Math 對象新增方法

// 剪掉小數(shù)這個尾巴
Math.trunc(3.141592653);

// 這是新增的一個有用的數(shù)學(xué)函數(shù)
Math.sign(Math.PI/2);  // => 1

// 這是 ES5 就有的三角函數(shù)
Math.sin(Math.PI/2);  // => 1

// 求立方根
Math.cbrt(27); // => 3

// 平方和的平方根 (計算空間距離很方便)
Math.hypot(1, 4, 8); // => 9

//還有很多對數(shù)函數(shù)的方法、雙曲線函數(shù)的方法
//...

一些對數(shù)蛹批、雙曲線函數(shù)的方法——除非是一些數(shù)據(jù)處理撰洗、科研等項目——在平時并不那么常用,因此不再羅列和展開描述了腐芍。

四差导、數(shù)值的其他擴展

數(shù)值的擴展,最后還增加了一些對整型猪勇、浮點型數(shù)據(jù)溢出的應(yīng)對方法设褐。這個需要在平日處理數(shù)據(jù)是特別注意一下。如果不清楚泣刹,則在需要的時候查看下文檔助析,就能輕易掌握。

正則表達(dá)式的擴展

正則表達(dá)式也許平時編程用得不多椅您,當(dāng)然也不見得外冀,因項目而異。如果覺得正則實在枯燥的朋友掀泳,可以先跳過本知識點雪隧,以后按需再學(xué)西轩。

對于剩下的觀眾,我們繼續(xù)膀跌。ES6 對正則的一些擴展還是非常有意義的遭商,也是有章可循的固灵。大概和前文關(guān)聯(lián)起來解讀捅伤,有這些擴展點:

  • 遷移。像數(shù)值的一些方法那樣巫玻,將正則相關(guān)的一些方法歸屬到合理的對象之下丛忆;
  • 增加了若干修飾符。尤其是修飾符 u仍秤,這和字符串的編碼格式的擴展遙相呼應(yīng)熄诡;
  • 后行斷言。這是對正則能力完備性的一個修復(fù)诗力;
  • 專門擴展了正則匹配時對 Unicode 字符的一些處理凰浮。這仍然呼應(yīng)上述第 2 條;
  • 屬名組匹配苇本。這是為語義清晰化做的一個擴展袜茧。

本節(jié)只挑 遷移, 后行斷言屬名組匹配 來講瓣窄,Unicode 再一次被冷落笛厦。

一、遷移

一時也找不到專業(yè)的描述俺夕,所以類似挪位置的都姑且叫 “遷移”裳凸。

字符串的與正則相關(guān)的方法,str.match()劝贸、str.replace()姨谷、str.search()str.split() 原本都放在 String.prototype 下實現(xiàn),現(xiàn)在 ES6 有更為合理的歸宿:

String.prototype.match() 
    => RegExp.prototype[Symbol.match]();
    
String.prototype.replace() 
    => RegExp.prototype[Symbol.replace]();
    
String.prototype.search() 
    => RegExp.prototype[Symbol.search]();
    
String.prototype.split() 
    => RegExp.prototype[Symbol.split]();

字符串的上述方法映九,最終調(diào)用的是 RegExp 上實現(xiàn)的方法梦湘。可見氯迂, ES6 內(nèi)部還是做了很多優(yōu)化調(diào)整的践叠。

二、后行斷言

ES5 正則表達(dá)式已經(jīng)提供這些斷言匹配:(?:pattern)嚼蚀、(?=pattern)禁灼、(?!pattern)。僅拿第二個來舉例:

// (?=26|27|28) 好比正則中的正則表達(dá)式
let reg = /Today(?=26|27|28)/g; 
// => 它能匹配到 'Today27' 中的 'Today'
// => 但無法匹配到 'Today29' 中的 'Today'
// => (?=pattern) 表達(dá)式只起到輔助驗證作用轿曙,如果驗證通過弄捕,則其輔佐的對象將成為最終的結(jié)果

可以看到僻孝,這種斷言是先有主體,再有輔助表達(dá)式守谓,意味著——如果輔助表達(dá)式匹配成功——前半部分就是本次全部匹配能夠獲取的目標(biāo)穿铆。

那問題來了,我想匹配到后面的目標(biāo)斋荞,而讓前半部分成為輔佐匹配荞雏,那豈不是難以辦到?確實平酿,筆者曾經(jīng)就遇到過這個麻煩凤优。

現(xiàn)在 ES6 正好彌補了這個缺陷,提供了 “后行斷言” 的規(guī)則蜈彼,只要在 “先行斷言” 的問號后加上 '<' 就是了筑辨。它們分別是:(?<:pattern)(?<=pattern)幸逆、(?<!pattern)棍辕。

let reg = /(?<=26|27|28)Today/g; 
// => 它能匹配到 '27Today' 中的 'Today'

三、屬名組匹配

ES5 其實也有屬名組还绘,就是匹配到一組 ( ) 中的值時楚昭,可以用特定的字符 $1/$2/$3 來表示。

這個看起來像模板字符串的東西蚕甥,大家想必都見過:

// $1/$2/$3 依次捕獲正則中的 '( )' 括號匹配到的值
let reg = /(\d{4})-(\d{2})-(\d{2})/;
'2017-8-27'.replace(reg, '$1/$2/$3');
// => '2017/8/27'

但是這樣仍然非常不直觀哪替,幾乎沒有語義化可言。ES6 的做法是菇怀,允許在匹配模式前加一個簽名比如 <year>凭舶,表明將來匹配到的這個內(nèi)容,直接賦值給了 year 變量爱沟。

let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let matched = reg.exec('2017-8-27');
let year = matched.groups.year; // => 2017
let month = matched.groups.month; // => 8
let day = matched.groups.day; // => 27

正則還有很多擴展沒有講到帅霜,但以上應(yīng)該是使用頻率比較高的幾個部分了。另外呼伸,ES6 對正則的擴展已深入到比較細(xì)致的部分身冀,也就是賦予了正則表達(dá)式更多的編程樂趣。

總結(jié)

以上對 JavaScript2015 基本類型中的字符串括享、數(shù)值以及 正則的擴展部分進行了梳理搂根,該部分比較簡單,也非沉逑剑瑣碎剩愧。但也能充分凸顯 ES6 相比 ES5 細(xì)節(jié)處變化之大。

下一篇《基本類型的擴展(二)》會講到數(shù)組娇斩、函數(shù)仁卷、對象的擴展穴翩。敬請期待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锦积,一起剝皮案震驚了整個濱河市芒帕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌丰介,老刑警劉巖背蟆,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異基矮,居然都是意外死亡淆储,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門家浇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碴裙,你說我怎么就攤上這事钢悲。” “怎么了舔株?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵莺琳,是天一觀的道長。 經(jīng)常有香客問我载慈,道長惭等,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任办铡,我火速辦了婚禮辞做,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寡具。我一直安慰自己秤茅,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布童叠。 她就那樣靜靜地躺著框喳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厦坛。 梳的紋絲不亂的頭發(fā)上五垮,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音杜秸,去河邊找鬼放仗。 笑死,一個胖子當(dāng)著我的面吹牛亩歹,可吹牛的內(nèi)容都是我干的匙监。 我是一名探鬼主播凡橱,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亭姥!你這毒婦竟也來了稼钩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤达罗,失蹤者是張志新(化名)和其女友劉穎坝撑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粮揉,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡巡李,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了扶认。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侨拦。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辐宾,靈堂內(nèi)的尸體忽然破棺而出狱从,到底是詐尸還是另有隱情,我是刑警寧澤叠纹,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布季研,位于F島的核電站,受9級特大地震影響誉察,放射性物質(zhì)發(fā)生泄漏与涡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一持偏、第九天 我趴在偏房一處隱蔽的房頂上張望驼卖。 院中可真熱鬧,春花似錦综液、人聲如沸款慨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檩奠。三九已至,卻和暖如春附帽,著一層夾襖步出監(jiān)牢的瞬間埠戳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工蕉扮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留整胃,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓喳钟,卻偏偏與公主長得像屁使,于是被迫代替她去往敵國和親在岂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容