參考規(guī)范:https://tc39.es/ecma262/。
Es6(es2015)
概述:
- 增強(qiáng)功能 包括模塊叛本、類聲明弦赖、詞法塊作用域喳挑、迭代器和生成器味赃,異步編程掀抹,解構(gòu)模式以及適當(dāng)?shù)奈膊空{(diào)用虐拓。
- 內(nèi)置庫(kù)的擴(kuò)展 支持?jǐn)?shù)據(jù)抽象心俗,包括Map, 集合Set, 以及二進(jìn)制數(shù)值的數(shù)組。對(duì)象以及數(shù)組功能的擴(kuò)展蓉驹。
第六版的重點(diǎn)開發(fā)工作始于2009年城榛,并于2015年6月通過,是經(jīng)過了15年的努力的結(jié)果态兴。作為常規(guī)版本存在狠持,對(duì)增量語言和庫(kù)增強(qiáng)功能提供了基礎(chǔ)。
因?yàn)镋s6已經(jīng)是大家耳熟能詳?shù)恼叭螅赃@里就不花篇幅了描述了喘垂,詳細(xì)見:es6教程
Es7(es2016)
在es6提出后,TC-39決議認(rèn)為耗時(shí)過長(zhǎng)不利于可持續(xù)發(fā)展绍撞,于是將發(fā)布周期轉(zhuǎn)換為每年發(fā)布一個(gè)版本正勒,以確保新的語言特性能夠更快的發(fā)展。
- Array.prototype.includes
- 新的指數(shù)運(yùn)算符
**
- 新的語法錯(cuò)誤
因?yàn)槊磕甓紩?huì)出一個(gè)版本傻铣,所以改動(dòng)不會(huì)像es6一樣那么大章贞,一個(gè)個(gè)來看一下:
-
Array.prototype.includes
規(guī)定: 其實(shí)在es6中已經(jīng)有 Array.prototype.includes 了, 只不過仍未完善非洲,所以出現(xiàn)在了es7的版本中鸭限。
兩個(gè)參數(shù):第一個(gè)要搜索的值蜕径,第二個(gè)開始搜索的索引位置(可選,默認(rèn)為0)败京。
返回值:找到返回true兜喻,找不到返回false。
let nums = [7, 8, 9]; // test console.log(nums.includes(7)); // true console.log(nums.includes(10)); // false console.log(nums.includes(7, 1)); // false
原因: 我們都知道在es6中存在多個(gè)類似功能的函數(shù)喧枷,比如:
findIndex(function)
虹统、find(function)
、indexOf(value)
那么為什么還會(huì)有includes
呢隧甚?
-
首先车荔,改名風(fēng)波:
Array.prototype.includes 的前身提案名是Array.prototype.contains ,但是沒有正式推出戚扳,于是很多網(wǎng)站自行hack了忧便。
假如規(guī)范實(shí)現(xiàn)
contains
, 會(huì)出現(xiàn)contains
無法被for..in
讀出來(因?yàn)閖s中所有原生提供的方法屬性都是不可枚舉的,只能通過屬性的屬性描述符獲取getOwnPropertyDescriptor(Array.prototype, 'indexOf')
)帽借,而之前自行hack的contains的是可以被讀出來的珠增。會(huì)出現(xiàn)代碼沒變動(dòng),在新規(guī)范推出后產(chǎn)生bug的情況砍艾。因此初稿階段蒂教,考慮新規(guī)范會(huì)使得許多現(xiàn)有網(wǎng)站出問題,所以改名
includes
脆荷。 -
其次凝垛,雖然我們用
indexOf
可以模擬includes
的行為,但出于語義描述不清楚的原因蜓谋,所以要改梦皮。includes
表達(dá)了 是否包含該項(xiàng)的意思。indexOf
表達(dá)了查找數(shù)組中第一次出現(xiàn)對(duì)應(yīng)元素的索引是什么桃焕,在針對(duì)返回的索引進(jìn)一步處理的意思剑肯。has
為什么不叫has呢,因?yàn)閔as一般表示key中是否有(Map.prototype.has
)观堂,includes表示value中是否有让网。 -
那么他的判斷是否相等的方式是什么呢?答案是:SameValueZero 师痕,es6中有4種相等算法
松散相等比較:實(shí)現(xiàn)接口
==
嚴(yán)格相等比較:實(shí)現(xiàn)接口
===
溃睹,使用Array.prototype.indexOf
,Array.prototype.lastIndexOf
和case-matching
SameValue: 實(shí)現(xiàn)接口
Object.is()
-
SameValueZero: 實(shí)現(xiàn)接口借用了
Map
和Set
的方法七兜。// 注意 // SameValue 中 +0 和 -0 是false Object.is(-0, +0); // false // SameValueZero 中 +0 和 -0 是true 和Set的判斷很像不是 const s = new Set(); s.add(0); s.has(-0); // true
思考: 從探究整個(gè)提案的流程丸凭,可以看出一個(gè)新特性的出現(xiàn)需要考慮很多方面的問題。
類比之下,我們的項(xiàng)目在修改的時(shí)候 惜犀,也需要考慮是否會(huì)對(duì)其他的東西產(chǎn)生影響铛碑,以及當(dāng)前的方案是否最優(yōu)。
思考一下虽界,我們現(xiàn)在有用到查詢數(shù)組中是否包含某個(gè)元素的情況汽烦,我猜測(cè)大多數(shù)都是用的indexOf
, 不過既然更優(yōu)的api,官方已經(jīng)提出來了 ,我們是否可以考慮換一下莉御,畢竟可以減少碼量撇吞,同時(shí)語義更加清晰不是。
let arr = [1, 2, 3];
if (arr.indexOf(1) > -1) {...}
// ==> 等價(jià)于
if (arr.includes(1)) {...}
-
語法變化:新的指數(shù)運(yùn)算符
**
規(guī)定: 雖然Math.pow() 是已經(jīng)支持了指數(shù)運(yùn)算的方法礁叔,但是正式的運(yùn)算符
**
看起來會(huì)會(huì)讓開發(fā)者更容易閱讀和理解牍颈。**
的左邊是基數(shù),右邊是指數(shù)琅关。 如下:let result = 10 ** 2; console.log(result); // 100 console.log(result === Math.pow(10, 2)) // true // 當(dāng)然 支持 **= 即 a = a**b <==> a **= b
原因: 沒錯(cuò) 煮岁,就是為了更容易書寫和閱讀。
思考: 官方都時(shí)刻關(guān)心涣易,可見容易書寫和閱讀多么的重要画机,我以為我們的代碼可以更加的簡(jiǎn)潔和易讀。推薦一個(gè)代碼規(guī)范地址:https://github.com/ryanmcdermott/clean-code-javascript
-
新的語法錯(cuò)誤
規(guī)定:在參數(shù)被解構(gòu)或者有默認(rèn)參數(shù)的函數(shù)中新症,禁止使用嚴(yán)格模式"use strict"指令步氏。否則會(huì)拋出錯(cuò)誤
// 正確 function good(first, second) { return first} // 拋出錯(cuò)誤 原因:有默認(rèn)參數(shù)并且使用了"use strict" function notGood(first, second = first) { "use strict"; return first; } // 拋出錯(cuò)誤 原因:參數(shù)被解構(gòu)并且使用了"use strict" function notGood2({first, second}) { "use strict"; return first; }
原因:實(shí)現(xiàn)運(yùn)行在嚴(yán)格模式下的參數(shù)非常困難,比如:
function foo(first = this) {
"use strict";
return first
}
在嚴(yán)格模式下first
被認(rèn)為是undefined徒爹,可是參數(shù)的默認(rèn)值也可以是函數(shù)(通過apply , call指定上下文的調(diào)用方式)荚醒,這就導(dǎo)致大多數(shù)的JavaScript引擎均不實(shí)現(xiàn)此功能,而是將其等同于全局對(duì)象瀑焦。
思考:當(dāng)我們遇到一個(gè)不好實(shí)現(xiàn)或者解決的問題的時(shí)候腌且,做個(gè)智者梗肝,未嘗不是一種明智的選擇(繞過它/拋異常)榛瓮。
Es8(es2017)
- Object、String的靜態(tài)方法
- 在函數(shù)參數(shù)列表中尾隨逗號(hào)并調(diào)用
- 異步功能巫击、共享內(nèi)存和原子
具體如下:
-
Object禀晓、String的靜態(tài)方法
規(guī)定: 擴(kuò)展了 Object和 String的功能
-
Object.values/Object.entries/Object.getOwnPropertyDescriptors()
Object.values
接受一個(gè)對(duì)象并返回所有值構(gòu)成的數(shù)組,其順序和for … in
的順序相同坝锰。Object.entries
接受一個(gè)對(duì)象并返回?cái)?shù)組粹懒,每個(gè)元素都是一個(gè)包含兩個(gè)元素的數(shù)組。第一個(gè)是對(duì)象的key, 第二個(gè)是對(duì)象的value顷级, 其順序和for … in
的順序相同凫乖。-
Object.getOwnPropertyDescriptors
獲取屬性描述符,即對(duì)象所有自己的屬性描述符。包括value/writable/enumerable/configurable
let obj = { one: 'hh', second: 'dd', thrid: 'zz' } Object.values(obj); // ["hh", "dd", "zz"] Object.entries(obj); // [["one", "hh"], ["second", "dd"], ["thrid", "zz"]] Object.getOwnPropertyDescriptor(obj, 'one'); // {value: "one", writable: true, enumerable: true, configurable: true}
-
String padding
用另一個(gè)字符串填充填充當(dāng)前字符串帽芽,直到結(jié)果字符串達(dá)到給定的長(zhǎng)度為止删掀,第二個(gè)參數(shù)默認(rèn)為空格。String.padStart(長(zhǎng)度, 填充字符串|' ')
從開頭填充, 填充字符從左往右填充-
String.padEnd(長(zhǎng)度, 填充字符串|' ')
從末尾向后填充导街,填充字符從左往右填充'abc'.padStart(10); // " abc" 'abc'.padStart(10, 'foo'); // "foofoofabc" 'abc'.padStart(6, '1234565'); // "123abc" 'abc'.padStart(8, '0'); // '00000abc' 'abc'.padStart(1); // 'abc' 'abc'.padEnd(10); // "abc " 'abc'.padEnd(10, 'foo');// "abcfoofoof" 'abc'.padEnd(6, '123456'); // 'abc123' 'abc'.padEnd(1); // 'abc'
-
思考:
Object.values
和 Object.keys
對(duì)應(yīng)使用披泪,
在對(duì)一些私密信息進(jìn)行處理的時(shí)候,需要將一些數(shù)字進(jìn)行加*隱藏搬瑰,之前的寫法可能是進(jìn)行遍歷數(shù)組逐個(gè)替換款票,現(xiàn)在有了padStart,可以這樣試一下:
// 對(duì)身份進(jìn)行隱藏顯示
const fullNumber = '320321197803069527';
// old
const hideLen = fullNumber.length - 4;
let maskedNumber = ''
for (let i = 0; i < fullNumber.length; i++) {
if (i < hideLen) {
maskedNumber += '*';
}else {
maskedNumber += fullNumber[i]
}
}
console.log(maskedNumber); // **************9527
// new
const last4Digits = fullNumber.slice(-4);
const maskedNumberNew = last4Digits.padStart(fullNumber.length, '*');
console.log(maskedNumberNew); // **************9527 很簡(jiǎn)潔泽论,思路很清晰不是
還有一種情形就是 給定字符串長(zhǎng)度艾少,超出的以省略號(hào)表示 (這里不考慮超出指定長(zhǎng)度省略號(hào)表示),試試看翼悴?
const str = 'Tom Jackson';
// 期望輸出: 'Tom...'
-
在函數(shù)參數(shù)列表中尾隨逗號(hào)并調(diào)用
規(guī)定:在函數(shù)的參數(shù)列表中姆钉,最后一個(gè)參數(shù)以逗號(hào)結(jié)尾,如:
function myFun( p1, p2, ) {} myFun( 'param1', 'param2', )
原因:
- 如果最后一項(xiàng)改變了位置抄瓦,則不必添加和刪除逗號(hào)潮瓶。
- 它可以幫助版本控制系統(tǒng)跟蹤實(shí)際更改的內(nèi)容。
-
異步功能
規(guī)定: 異步功能钙姊,指的是定義一個(gè)異步函數(shù)毯辅,也就是一個(gè)返回異步對(duì)象的函數(shù),返回
Promise
或者函數(shù)上加async
標(biāo)記煞额。
原因:當(dāng)異步功能有多個(gè)的時(shí)候思恐,在一個(gè)函數(shù)中就會(huì)難以維護(hù),違背了單一職責(zé)原則膊毁, 就需要拆分出不同的方法胀莹,因此就有了異步功能。
思考: 異步功能很好的將業(yè)務(wù)封裝在了功能函數(shù)之中婚温,調(diào)用者只需要關(guān)心成功和失敗兩種狀態(tài)(resolve和reject)描焰,這樣會(huì)使得代碼更具有可讀性。
這種場(chǎng)景目前用的最多的是在接口函數(shù)的編寫中栅螟,它讓我們不用太過關(guān)心接口的發(fā)送以及對(duì)返回?cái)?shù)據(jù)的處理荆秦,只需要使用即可。
-
共享內(nèi)存和原子
規(guī)定: 引入新的構(gòu)造函數(shù)
SharedArrayBuffer
和 具有輔助函數(shù)的命名空間對(duì)象Atomics
力图, 用原子操作進(jìn)行通信的程序步绸,即使在并行CPU上也能確保定義良好的執(zhí)行順序。全局變量Atomics
吃媒,它的方法具有三個(gè)主要用例瓤介。- 同步化
- 等待通知
- 原子操作
Atomics.store() // 寫入 Atomics.load() // 讀取 Atomics.wait() // 等待 Atomics.wake() // 喚醒
原因: 雖然用到的地方很少吕喘,但是作為一門語言,對(duì)于并行操作還是要支持的刑桑。Web workers 將任務(wù)并行引入了 JavaScript 兽泄。還記得PWA嗎?它的核心就在與本地開啟了一個(gè)service worker漾月,并對(duì)數(shù)據(jù)進(jìn)行了緩存以及代理病梢。
思考: 要實(shí)現(xiàn)并行,需要滿足兩點(diǎn):一個(gè)是數(shù)據(jù)的并行梁肿,一個(gè)是代碼的并行蜓陌。這里
SharedArrayBuffer
作為共享陣列緩沖區(qū)是更高抽象的基本構(gòu)建塊。 它允許多個(gè)workers和主線程之間共享SharedArrayBuffer
對(duì)象的字節(jié)吩蔑。同時(shí)Atomics
的 方法可以用來與其他 workers 進(jìn)行同步钮热。詳情可以了解
https://www.html.cn/archives/7724
Es9(es2018)
- 解除模板字面量限制
- 正則表達(dá)式相關(guān)
- 對(duì)象解構(gòu)中的rest操作符(...)/對(duì)象字面量中的spread操作符(...)
- Promise.prototype.finally 和 異步的迭代
具體如下:
-
解除模版字面量的限制
規(guī)定: 對(duì)于模版字面量中,如果存在非法轉(zhuǎn)義字符 烛芬,則將模版字面量設(shè)置為undefined隧期。不過可以通過.raw訪問原始值。
function tag(strs) { console.log(strs[0] === undefined); console.log(strs.raw[0] === '\\unicode and \\u{55}') } tag`\unicode and \u{55}`; // true true const badSequence = `bad escape sequence: \unicode`; // Uncaught SyntaxError: Invalid Unicode escape sequence
原因:解決模版字面量中存在非法轉(zhuǎn)義字符報(bào)錯(cuò)的問題赘娄。
思考:在處理字符串的時(shí)候仆潮,我們多是需要注意處理需要進(jìn)行轉(zhuǎn)義的字符,此時(shí)有了這個(gè)特性 遣臼,使的我們可以封裝個(gè)公共的方法性置,放心的使用模版字面量,沒必要進(jìn)行而外的處理了揍堰。
-
正則表達(dá)式相關(guān)
-
.
的使用規(guī)定: es9支持了/s模式下鹏浅,
.
可以匹配換行符。console.log(/./s.test("\n")); // true console.log(/./s.test("\r")); // true
原因:正則中
.
看似可以匹配任何字符屏歹,但換行符除外隐砸,當(dāng)時(shí)大家用[\w\W]替代了.
。這個(gè)終究是個(gè)缺陷蝙眶。于是增加了在 /s 模式下季希,.
=>[\w\W]
。
-
-
對(duì)捕獲組進(jìn)行命名:
規(guī)定: 使用捕獲組需要通過指定捕獲組名稱來進(jìn)行引用械馆,每個(gè)名稱是唯一的胖眷,避免沖突武通。語法:
?<name>
const regExp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u; const result = regExp.exec('2020-10-21'); console.log(result.groups.year === '2020'); //true => result[1] === '2020' console.log(result.groups.month === '10'); //true => result[2] === '10' console.log(result.groups.day === '21');//true => result[3] === '21' // 其中 result[0] === '2020-10-21' // 命名捕獲組這塊 建議結(jié)合解構(gòu)字面量一起使用 會(huì)更加清晰 const { groups: { year, month, day } } = regExp.exec('2020-10-21');
原因:對(duì)捕獲組命名可以讓調(diào)用更加清晰霹崎。
-
支持了后行斷言:
規(guī)定: es9之前只支持先行斷言,現(xiàn)在支持了后行斷言冶忱。
正向后行斷言:(?<=...) 表示之前的字符串能匹配
const re = /(?<=\d{3}) meters/; // 表示 meters 之前 匹配三個(gè)數(shù)字 console.log(re.test('10 meters')); // false console.log(re.test('100 meters')); // true
負(fù)向后行斷言:(?<!...) 表示之前的字符串不能匹配
const re = /(?<!\d{3}) meters/; // 表示 meters 之前 不能匹配三個(gè)數(shù)字 console.log(re.test('10 meters')); // true console.log(re.test('100 meters')); // false
原因: 彌補(bǔ)之前只能支持先行斷言的缺陷尾菇。
思考: 正則中完整的斷言定義:正/負(fù)向斷言 與 先/后行斷言 的笛卡爾積組合(互相組合得到4種結(jié)果)。
補(bǔ)充一下
正向先行斷言
和負(fù)向先行斷言
// 正向先行斷言 const re = /meters(?= 10)/; console.log(re.test('meters 10')); // true console.log(re.test('meters 5')); // false // 負(fù)向先行斷言 const re2 = /meters(?! 10)/; console.log(re.test('meters 10')); // false console.log(re.test('meters 5')); // true
-
Unicode 屬性轉(zhuǎn)義
規(guī)定:正則支持了更加強(qiáng)大的unicode匹配方式疟羹。在
/u
(修飾符u指unicode)模式下温赔,通過\p{}大括號(hào)內(nèi)提及unicode字符屬性來匹配字符肠仪。可以用
\p{Number}
匹配所有數(shù)字可以用
\p{Alphabetic}
匹配所有Alphabetic元素衰絮,包括漢字惭载,字母等可以用
\p{White_Space}
匹配空格泳猬、制表符制轰、換行符灯谣。等等缆八。
const regex = /^\p{Number}+$/u; regex.test("231???"); // true regex.test("???"); // true regex.test("ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ"); // true const str = "漢"; console.log(/\p{Alphabetic}/u.test(str)); // true // the \w shorthand cannot match 漢 console.log(/\w/u.test(str)); // false /^\p{White_Space}+$/u.test('\n \r \t'); // true
原因: 創(chuàng)建支持unicode的正則表達(dá)式不再麻煩曲掰,更加易讀。使用Unicode屬性轉(zhuǎn)義符的代碼將保持“最新”狀態(tài):每當(dāng)Unicode標(biāo)準(zhǔn)得到更新時(shí)奈辰,ECMAScript引擎就會(huì)更新其數(shù)據(jù)栏妖。
-
對(duì)象解構(gòu)中的rest操作符(...)/對(duì)象字面量中的spread操作符(...)
// 對(duì)象解構(gòu)中的rest操作符(...) const {one, two, ...others} = { one: 'one', two: 'two', three: 'three', four: 'four'}; console.log(others); // { three: 'three', four: 'four' } // 對(duì)象字面量中的spread操作符(...) const nums = {one, two, ...others}; console.log(nums);// { one: 'one', two: 'two', three: 'three', four: 'four'};
**思考: **需要注意的是 在使用對(duì)象字面量的時(shí)候 如果有key重復(fù),那么對(duì)象中后面的key的值會(huì)覆蓋前面的奖恰。
-
Promise.prototype.finally 和 異步的迭代
-
Promise.prototype.finally
規(guī)定:一旦執(zhí)行了Promise的resolve回調(diào)或者reject回調(diào)吊趾,最終都會(huì)執(zhí)行finally回調(diào)
思考:總有一些相同的處理需要在resolve回調(diào)或者reject回調(diào)后處理,比如:資源的回收或者網(wǎng)絡(luò)請(qǐng)求時(shí)loading的狀態(tài)修改等瑟啃。 平時(shí)我們會(huì)在resolve回調(diào)或者reject回調(diào)中都添加或者提取一個(gè)公共方法÷鄯海現(xiàn)在會(huì)讓我們更省力和美觀。
-
異步的迭代
規(guī)定:這個(gè)是
for...of
的一種變體蛹屿,他允許在由異步組成的可迭代對(duì)象上進(jìn)行迭代孵奶。async function asyncFun() { const promises = [ fetch('f1.json'), fetch('f2.json'), fetch('f3.json'), ]; // 正常的迭代 for (const promiseItem of promises) { console.log(item); // => 輸出 promise } // 正常的迭代 for await (const promiseItem of promises) { console.log(item); // => 輸出 resolved response } }
思考: 適合的場(chǎng)景會(huì)是 多個(gè)異步同步執(zhí)行,并對(duì)每個(gè)結(jié)果有統(tǒng)一的處理方式蜡峰。比如:對(duì)文件的處理了袁。
-
Es10(es2019)
Array.prototype.flat 和 Array.prototype.flatMap
Object.fromEntries
String.prototype.trimStart, String.prototype.trimEnd
Symbol的描述訪問器
try { } catch {} 可省略catch參數(shù)的寫法
對(duì)行分隔符
\u2028
和段落分隔符\u2029
的支持,JSON.stringify對(duì)特殊字符的轉(zhuǎn)義處理
Array.prototype.sort
Function.prototype.toString
具體如下:
-
Array.prototype.flat 和 Array.prototype.flatMap
規(guī)定:
Array.prototype.flat(Number) 湿颅,降緯度數(shù)組载绿,具體下降多少維度視參數(shù)而定,知道無法繼續(xù)降維為止油航。默認(rèn)為1
Array.prototype.flatMap(Function) 崭庸,flat和map功能的組合,接受一個(gè)函數(shù), 返回一個(gè)處理后的降維了1個(gè)的數(shù)組谊囚。
const fruits = [['apple', 'banana'], ['蘋果', '香蕉']]; console.log(fruits.flat()); // ['apple', 'banana', '蘋果', '香蕉'] const fruits2 = [['apple'], ['banana'], ['蘋果'], ['香蕉']]; const mappedAndFlatten = fruits2.flatMap((fruit, index) => [fruit + '_fruit']); console.log(mappedAndFlatten); // ["apple_fruit", "banana_fruit", "蘋果_fruit", "香蕉_fruit"]
思考:
對(duì)比我們平常使用的解構(gòu)方法, 需要遞歸遍歷:
function reduceDimension(arr){ let ret = []; let targetArr = function(arr){ arr.forEach(function(item){ item instanceof Array ? targetArr(item) : ret.push(item); }); } targetArr(arr); return ret; } // 等同于 arr.flat(Infinity)
發(fā)現(xiàn)
flat(Infinity)
無疑更簡(jiǎn)潔(Infinity 作為數(shù)值中的無限大怕享,可以保證數(shù)組能夠完全解構(gòu))。
-
Object.fromEntries
規(guī)定: 將 由鍵值對(duì)組成的數(shù)組轉(zhuǎn)換成一個(gè)對(duì)象, 與
Object.entries
功能相反镰踏。const fruits = { apple: '蘋果', banana: '香蕉', orange: '橘子'}; const entries = Object.entries(fruits);// [["apple", "蘋果"],["banana", "香蕉"] ,["orange", "橘子"]] const fromEntries = Object.fromEntries(entries); // { apple: '蘋果', banana: '香蕉', orange: '橘子'}
思考: 這是針對(duì)這種特定數(shù)據(jù)結(jié)構(gòu)的格式化 函數(shù)函筋。對(duì)于一個(gè)對(duì)象如果需要同時(shí)修改對(duì)象的key-value, 直接修改不方便,我們可以先將一個(gè)對(duì)象通過
Object.entries
轉(zhuǎn)換成數(shù)組奠伪,進(jìn)行修改跌帐,完成后通過Object.fromEntries
轉(zhuǎn)換回來首懈。
-
String.prototype.trimStart, String.prototype.trimEnd
trimStart :去除字符串前面的空格
trimEnd: 去除字符串后面的空格
-
Symbol的描述訪問器
規(guī)定: 通過 Symbol.prototype.description可以獲取定義Symbol時(shí)的具體數(shù)值
const OPEN = Symbol('STATUS_OPEN'); // old 可以通過 toString() 來獲取描述信息 console.log(OPEN.toString()); // "Symbol('STATUS_OPEN')" // new 通過 description屬性獲取 console.log(OPEN.description); // "STATUS_OPEN"
思考: Symbol的出現(xiàn) 讓我們?cè)诔A康氖褂弥写罅渴褂茫贿^有時(shí)侯需要獲取它的描述值來做一些判斷谨敛。
const BANNER = { LEFT: Symbol('left'), RIGHT: Symbol('right'), } // 使用時(shí)候 if (BANNER.LEFT.description === 'left') { // do something }
-
try { } catch {} 可省略catch參數(shù)的寫法
規(guī)定: catch后面的括號(hào)以及參數(shù)在不用的時(shí)候可以省略
try { } catch(err) {} try { } catch {} // 不會(huì)報(bào)錯(cuò)
思考:有些時(shí)候我們不需要對(duì)catch 的err 數(shù)據(jù)進(jìn)行操作究履,這個(gè)時(shí)候如果傳遞了,但是未使用脸狸,那么eslint 可能會(huì)警告我們代碼中存在可優(yōu)化最仑。本著不用不寫的原則,省略無疑是很好的一種方式炊甲。
-
對(duì)行分隔符
\u2028
和段落分隔符\u2029
的支持規(guī)定: es10之前
'\u2028'
和'\u2020'
這種寫法會(huì)報(bào)錯(cuò)盯仪,現(xiàn)在不會(huì)啦。
-
JSON.stringify對(duì)特殊字符的轉(zhuǎn)義處理
規(guī)定: JSON.stringify 在處理
\uD800
到\DFFF
之間的字符蜜葱,如果找不到對(duì)應(yīng)的全景,直接返回轉(zhuǎn)義后的字符。JSON.stringify('\uDF06\uD834'); // '"\\udf06\\ud834"'
-
Array.prototype.sort
規(guī)定: es10之前 V8對(duì)于包含10個(gè)以上的數(shù)組排序時(shí)采用了不穩(wěn)定的快速排序算法牵囤,這個(gè)算法可能會(huì)改變?cè)瓉頂?shù)組里面相同數(shù)值的元素的先后關(guān)系爸黄。 通過采用原地排序保證數(shù)組中相同數(shù)值元素的先后關(guān)系。避免了順序被改變的問題揭鳞。
-
Function.prototype.toString
規(guī)定:返回一個(gè)表示函數(shù)源代碼的字符串炕贵,包括格式和注釋,比較精確野崇。
function add(num1, num2) { /* add */ return num1 + num2; } add.toString(); // "function add(num1, num2) { // /* add */ // return num1 + num2; // }"
Es11(es2020)
String.prototype.matchAll
Promise.allSettled
export * as ns from 'module'
for-in 對(duì)于迭代對(duì)象順序的統(tǒng)一
鏈合并運(yùn)算符
?.
以及 Null判斷運(yùn)算符??
新增原始類型 BigInt 称开,可以表示任意精度的整數(shù)
import 動(dòng)態(tài)導(dǎo)入
import.meta
標(biāo)準(zhǔn)化的全局對(duì)象
具體如下:
-
String.prototype.matchAll
規(guī)定: 返回所有與正則表達(dá)式相匹配字符串的結(jié)果的迭代器,包括捕獲組乓梨。相比于match, 它提供的信息更全鳖轰。
const regexp = /t(e)(st(\d?))/g; const str = 'test1test2'; // 曾經(jīng) 我們通過 while 和 exec配合來獲取比較全的匹配信息 let result = null; while((result = regexp.exec(str)) !== null) { console.log(result); } // > ["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined] // > ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined] // 現(xiàn)在 我們用matchAll 就好了 const array = [...str.matchAll(regexp)]; for (result of array) { console.log(result); } // > ["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined] // > ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined]
-
Promise.allSettled
規(guī)定:對(duì)比Promise.all 方法,Promise.allSettled 當(dāng)每個(gè)Promise 無論失敗還是成功都會(huì)走回調(diào)函數(shù)扶镀。
const promiseArr = [ Promise.resolve(100), Promise.reject(null), Promise.reject(new Error('Oh No')), ] Promise.all(promiseArr).then(results => { // 不會(huì)執(zhí)行 console.log('All Promise Settled', results); }); Promise.allSettled(promiseArr).then(results => { console.log('All Promise Settled', results); }); // [{status: "fulfilled", value: 100}, // {status: "rejected", reason: null}, // {status: "rejected", reason: Error: Oh No at <anonymous>:4:20}]
思考:當(dāng)我們?cè)谶M(jìn)行多個(gè)接口請(qǐng)求的時(shí)候蕴侣,如果通過Promise.all ,不能保證回調(diào)一定會(huì)執(zhí)行臭觉,這時(shí)候如果有l(wèi)oading狀態(tài)的昆雀,無疑會(huì)出現(xiàn)問題,無法在回調(diào)中更新蝠筑。如果我們并不關(guān)心接口是否調(diào)用成功狞膘,這個(gè)時(shí)候Promise.allSettled 無疑是更合適的。
-
export * as ns from 'module'
規(guī)定: 在一個(gè)文件中引用另外一個(gè)文件并導(dǎo)出他的一種縮寫什乙。
export * as utils from './utils.mjs' // 等價(jià)于 ==> import * as utils from './utils.mjs' export { utils }
思考: 在react中使用組件的時(shí)候挽封,我們會(huì)對(duì)一個(gè)目錄下的多個(gè)文件 通過
index.js
導(dǎo)出。好處在于當(dāng)前文件中并不會(huì)真的導(dǎo)入文件對(duì)象的引用稳强,比如以上的utils為undefined场仲。// index.js old import * as Header from './header.jsx' import * as Footer from './footer.jsx' // ... export { Header } export { Footer } // ... // index.js new export * as Header from './header.jsx'; export * as Footer from './footer.jsx'; export * as Body from './body.jsx'; export * as Nav from './nav.jsx';
-
for-in 對(duì)于迭代對(duì)象順序的統(tǒng)一
規(guī)定:雖然瀏覽器自己保持了
for in
的順序和悦,但是在es11中進(jìn)行了標(biāo)準(zhǔn)化退疫。
-
鏈合并運(yùn)算符
?.
以及 Null判斷運(yùn)算符??
規(guī)定:鏈合并運(yùn)算符 避免了調(diào)用時(shí)左側(cè)的對(duì)象是否為null或undefined的判斷渠缕,Null判斷運(yùn)算符 為屬性值為null或undefined時(shí),指定默認(rèn)值
const userName = (list && list.info && list.info.base && list.info.base.userName ) || 'userName'; // => 等價(jià)于 const userName = list?.info?.base?.userName ?? 'userName';
思考:
??
類似于||
褒繁,區(qū)別在于:??
只當(dāng)左側(cè)為null/undefined
的時(shí)候才會(huì)指定右側(cè)默認(rèn)值-
||
當(dāng)左側(cè)所有轉(zhuǎn)換后boolean值為false 的時(shí)候會(huì)指定右側(cè)默認(rèn)值(包括 0 )在某些情況下 我們并不需要這種結(jié)果亦鳞,因此結(jié)合業(yè)務(wù)考慮使用哪一種。
-
新增原始類型 BigInt 棒坏,可以表示任意精度的整數(shù)
規(guī)定: 顧名思義燕差,就是用來存放Number放不下的數(shù)字
let maxNum = 9007199254740992; // Number的最大值 pow(2, 53) - 1 console.log(maxNum + 1); // 9007199254740992 maxNum = 9007199254740992n; console.log(maxNum + 1n); // 9007199254740993n console.log(typeof maxNum === 'bigint'); // true console.log(maxNum + 1); // Uncaught TypeError: Cannot mix BigInt and other types
思考: 在進(jìn)行大數(shù)計(jì)算的時(shí)候,之前需要通過豎式運(yùn)算坝冕,一種從個(gè)位往前一個(gè)一個(gè)相加求和的方式徒探,比較麻煩。現(xiàn)在直接用BigInt就可以了
-
import 動(dòng)態(tài)導(dǎo)入
規(guī)定: 返回所請(qǐng)求模塊的模塊名稱空間對(duì)象的Promise喂窟,所以也可以使用async/await
const modulePath = './file.js'; import(modulePath) .then((module) => { // do something }); // or (async function() { const modulePath = './file.js'; const module = await import(modulePath); // do somthing })();
思考:import 的動(dòng)態(tài)導(dǎo)入支持 一方面可以讓我們按需加載测暗,另一方面的可能會(huì)出現(xiàn)濫用的可能,對(duì)靜態(tài)文件分析造成一定程度上的阻礙(比如:tree-shaking 就是依賴于 import的靜態(tài)導(dǎo)入磨澡,如果都做成了動(dòng)態(tài)導(dǎo)入碗啄,那么該功能的能力會(huì)收到很大的影響)。
-
import.meta
規(guī)定: 可以通過import.meta獲取module的信息
<script type="module" src="module.js"></script> // module.js console.log(import.meta) // 得到一個(gè)對(duì)象 包含模塊的信息{ url: "file:///home/user/module.js" }
思考:在使用一個(gè)模塊時(shí)稳摄,有時(shí)需要知道模板本身的一些信息(比如模塊的路徑)稚字。這是import.meta的用處。
-
標(biāo)準(zhǔn)化的全局對(duì)象
規(guī)定:全局變量之前在各個(gè)平臺(tái)未統(tǒng)一厦酬,需要自行標(biāo)準(zhǔn)化胆描。
var getGlobal = function () { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } throw new Error('unable to locate global object'); } // getGlobal() 等同于 globalThis
其他可能的提案
do表達(dá)式
雙冒號(hào)運(yùn)算符
管道運(yùn)算符
#!
命令
具體如下:
-
do表達(dá)式
規(guī)定: 通過在塊級(jí)作用域前添加do , 讓塊級(jí)作用域可以變?yōu)楸磉_(dá)式仗阅。也就是說可以返回值袄友。do 也提供了單獨(dú)的作用域。do表達(dá)式的邏輯:封裝什么就會(huì)返回什么
let x = do { let t = f(); t * t + 1; }; // x的值等于 t*t+1的結(jié)果 // 等同于 <表達(dá)式> do { <表達(dá)式>; } // 等同于 <語句> do { <語句> }
思考:我們?cè)趯慾sx的時(shí)候霹菊,do很好用剧蚣。以下避免了三元運(yùn)算符的使用,同時(shí)代碼意圖比較清晰旋廷。
return ( <nav> <Home /> { do { if (loggedIn) { <LogoutButton /> } else { <LoginButton /> } } } </nav> )
-
雙冒號(hào)運(yùn)算符
規(guī)定:即“函數(shù)綁定”(function bind)運(yùn)算符鸠按,用來取代
call
、apply
饶碘、bind
調(diào)用目尖。左邊是一個(gè)對(duì)象,右邊是一個(gè)函數(shù)foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments)
-
管道運(yùn)算符
規(guī)定:JavaScript 的管道是一個(gè)運(yùn)算符扎运,寫作
|>
瑟曲。它的左邊是一個(gè)表達(dá)式饮戳,右邊是一個(gè)函數(shù)。支持await洞拨。x |> f // 等同于 f(x) x |> await f // 等同于 await f(x)
思考:管道運(yùn)算符最大的好處扯罐,就是可以把嵌套的函數(shù),寫成從左到右的鏈?zhǔn)奖磉_(dá)式烦衣。
function doubleSay (str) { return str + ", " + str; } function capitalize (str) { return str[0].toUpperCase() + str.substring(1); } function exclaim (str) { return str + '!'; } let msg = 'hello'; const result = msg |> doubleSay |> capitalize |> exclaim; // 等同于 const resultNew = exclaim(capitalize(doubleSay(msg)));
-
#!
命令規(guī)定: JavaScript 腳本引入了
#!
命令歹河,寫在腳本文件或者模塊文件的第一行。Unix 命令行就可以直接執(zhí)行腳本花吟。同時(shí)對(duì)于JavaScript 引擎來說秸歧,會(huì)把#!
理解成注釋,忽略掉這一行衅澈。// 寫在腳本文件第一行 hello.js #!/usr/bin/env node 'use strict'; console.log(1); # 以前執(zhí)行腳本的方式 $ node hello.js # 現(xiàn)在執(zhí)行 的方式 $ ./hello.js