1. ES6 (ECMAScript 2015)
1.1. let和const
let
定義的變量巩剖,只能在塊作用域里訪問铝穷,不能跨塊訪問,也不能跨函數(shù)訪問佳魔。
const
用來定義常量曙聂,使用時(shí)必須初始化(即必須賦值),只能在塊作用域里訪問鞠鲜,而且不能修改宁脊。
{
var a = 1
let b = 2
const c = 3
}
console.log(a) // 1
console.log(b) // Uncaught ReferenceError: b is not defined
console.log(c) // Uncaught ReferenceError: c is not defined
const d = 4
d = 5 // Uncaught TypeError: Assignment to constant variable.
注意:const定義的對(duì)象屬性是否可以改變?
可以贤姆,因?yàn)閷?duì)象是引用類型榆苞,const僅保證指向?qū)ο蟮闹羔槻话l(fā)生改變,而修改對(duì)象的屬性不會(huì)改變對(duì)象的指針庐氮,所以是被允許的
1.2. 類 (class)
class Bird {
constructor(name) {
this.name = name;
}
fly() {
console.log('fly...');
}
}
const eagle = new Bird('Eagle')
eagle.fly() // fly...
1.3. 模塊化(ES Module)
支持通過import
引入類和方法
// A.js
export const add = (a, b) => a + b
// B.js
import { add } from './A'
console.log(add(1, 2)) // 3
1.4. 箭頭函數(shù) (Arrow Function)
const add = (a, b) => a + b;
add(1, 2) // 3
1.5. 函數(shù)參數(shù)默認(rèn)值
function func(name = 'danny',age = 23){
// code
}
1.6. 模板字符串 (Template String)
通過反引號(hào)`
構(gòu)造模板字符串
let name = 'danny'
let age = 23
let str = `My name is ${name},I am ${age} years old.`
console.log(str) // My name is danny,I am 23 years old.
1.7. 解構(gòu)賦值(Destructuring)
通過解構(gòu)賦值, 可以將屬性/值從對(duì)象/數(shù)組中取出,賦值給其他變量语稠。
let arr = [0,1,2]
let [a,b,c] = arr
console.log(a) // 0
console.log(b) // 1
console.log(c) // 2
let {name,age} = {name:'danny',age:23}
console.log(name) // danny
console.log(age) // 23
let [a, b, c, d, e] = 'hello';
console.log(a) // a = 'h'
console.log(b) // b = 'e'
console.log(c) // c = 'l'
console.log(d) // d = 'l'
console.log(e) // e = 'o'
1.8. 延展操作符(Spread Operator)
let a = [...'hello world']; // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
1.9. 對(duì)象屬性簡(jiǎn)寫
let name = 'danny';
let person = {
name: name;
};
//等同于
let name = 'danny';
let person = {
name;
};
1.10. Promise
防止回調(diào)地獄
// 聲明一個(gè)Promise對(duì)象
let promise = new Promise(function(resolve, reject) {
// ... some code
if (success){
resolve(value);
} else {
reject(error);
}
});
promise.then(
() => { console.log('this is success callback') }
).catch(
(err) => { console.log(err) }
).then(
...
).catch(
...
)
2. ES7 (ECMAScript 2016)
2.1. Array.prototype.includes()
["a","b"].includes("a") // true
["a","b"].includes("c") // false
2.2. 指數(shù)操作符
2**10; // 1024
3. ES8 (ECMAScript 2017)
3.1.async/await
async getData(){
const res = await api.getTableData(); // await 異步任務(wù)
// do something
}
3.2. Object.values()
Object.values({a: 1, b: 2, c: 3}); // [1, 2, 3]
3.3. Object.entries()
Object.entries({a: 1, b: 2, c: 3}); // [["a", 1], ["b", 2], ["c", 3]]
3.4. String padding
// padStart
'hello'.padStart(10); // " hello"
// padEnd
'hello'.padEnd(10) "hello "
3.5. 自動(dòng)忽略函數(shù)參數(shù)列表/對(duì)象字面量/數(shù)組結(jié)尾處逗號(hào)
function foo(param1, param2,) {}
let obj = {first: 'Jane',last: 'Doe',}
let arr = ['red','green', 'blue',]
3.6. Object.getOwnPropertyDescriptors()
返回指定對(duì)象所有自身屬性(非繼承屬性)的描述對(duì)象。
該方法的引入目的弄砍,主要是為了解決Object.assign()
無法正確拷貝 get 屬性和 set 屬性的問題。
const clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
3.7. SharedArrayBuffer
SharedArrayBuffer
對(duì)象用來表示一個(gè)通用的输涕,固定長(zhǎng)度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)音婶,類似于 ArrayBuffer
對(duì)象,它們都可以用來在共享內(nèi)存(shared memory)上創(chuàng)建視圖莱坎。與 ArrayBuffer
不同的是衣式,SharedArrayBuffer
不能被分離。
new SharedArrayBuffer(length)
3.8. Atomics
Atomics
對(duì)象提供了一組靜態(tài)方法對(duì) SharedArrayBuffer
和 ArrayBuffer
對(duì)象進(jìn)行原子操作。碴卧、
4. ES9 (ECMAScript 2018)
4.1. 異步迭代
await
可以和for...of
循環(huán)一起使用弱卡,以串行的方式運(yùn)行異步操作
async function process(array) {
for await (let i of array) {
// doSomething(i);
}
}
4.2. Promise.finally()
Promise.resolve().then().catch(e => e).finally();
4.3. Rest/Spread 屬性
可以簡(jiǎn)單理解rest
為收集,spread
為展開
用于對(duì)象解構(gòu)的rest
操作符住册,目前這個(gè)操作符只能在數(shù)組解構(gòu)和參數(shù)定義中使用
const obj = {foo: 1, bar: 2, baz: 3};
const {foo, ...rest} = obj;
console.log(rest) // {bar: 2, baz: 3}
如果你正在使用對(duì)象解構(gòu)來處理命名參數(shù)婶博,rest 操作符讓你可以收集所有剩余參數(shù)
function func(param1, param2, ...rest) { // rest operator
console.log('All parameters: ',param1, param2, ...rest); // spread operator
}
fuc(1,2,3,4,5) // All parameters: 1 2 3 4 5
對(duì)象字面量中的 spread
操作符,目前這個(gè)操作符只能用于數(shù)組字面量和在函數(shù)方法中調(diào)用荧飞。
const obj = {foo: 1, bar: 2, baz: 3};
{...obj, qux: 4} // { foo: 1, bar: 2, baz: 3, qux: 4 }
4.4. 正則表達(dá)式s標(biāo)記(dotAll)
ES9之前凡人,在正則中.
可以匹配任意字符,除了換行符\n
叹阔。
/hello.es9/.test('hello\nes9') // false
/hello.es9/.test('hello\tes9') // true
ES9引入了dotAll模式挠轴,通過使用標(biāo)記s選項(xiàng),.就可以匹配換行符耳幢。
/hello.es9/s.test('hello\nes9') // true
4.5. 正則表達(dá)式命名捕獲組(Named capture groups)
ES9之前岸晦,正則表達(dá)式中小括號(hào)匹配的分組是通過索引編號(hào)的
const reg = /(\d{4})-(\d{2})-(\d{2})/u;
const matched = reg.exec('2021-01-05');
matched[0]; // 2021-01-05
matched[1]; // 2021
matched[2]; // 01
matched[3]; // 05
ES9允許命名捕獲組使用符號(hào)?<name>
,可以指定小括號(hào)中匹配內(nèi)容的名稱放在groups里睛藻,這樣可以提高代碼的可讀性启上。
const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const matched = reg.exec('2021-01-05');
matched.groups.year; // 2021
matched.groups.month; // 01
matched.groups.day; // 05
//命名捕獲組也可以使用在replace()方法中。例如將日期轉(zhuǎn)換為“年月日”格式:
const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2018-12-31'.replace(reg, '$<year>年$<month>月$<day>日'); // 2018年12月31日
4.6. 反向斷言 (lookbehind)
(?=pattern):正向肯定預(yù)查修档,在任何匹配pattern的字符串開始處匹配查找字符串碧绞。這是一個(gè)非獲取匹配,也就是說吱窝,該匹配不需要獲取供以后使用讥邻。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”院峡,但不能匹配“Windows3.1”中的“Windows”兴使。
(?!pattern):正向否定預(yù)查,在任何不匹配pattern的字符串開始處匹配查找字符串照激。這是一個(gè)非獲取匹配发魄,也就是說,該匹配不需要獲取供以后使用俩垃。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”励幼,但不能匹配“Windows2000”中的“Windows”。
(?<=pattern): 反向肯定預(yù)查口柳,與正向肯定預(yù)查類似苹粟,只是方向相反。例如跃闹,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”嵌削,但不能匹配“3.1Windows”中的“Windows”毛好。
(?<!pattern):反向否定預(yù)查,與正向否定預(yù)查類似苛秕,只是方向相反肌访。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”艇劫。
4.7. 正則表達(dá)式 Unicode 轉(zhuǎn)義
Unicode屬性轉(zhuǎn)義吼驶,形式為\p{...}和\P{...},在正則表達(dá)式中使用標(biāo)記u(unicode) 選項(xiàng)港准。
/^\p{White_Space}+$/u.test(' ') // 匹配空格
/^\p{Script=Greek}+$/u.test('μετ?') // 匹配希臘字母
/^\p{Script=Latin}+$/u.test('Grü?e') // 匹配拉丁字母
/^\p{Surrogate}+$/u.test('\u{D83D}') // 匹配單獨(dú)的替代字符
5. ES10 (ECMAScript 2019)
5.1. Array.flat()和Array.flatMap()
flat()
[1, 2, [3, 4]].flat(Infinity); // [1, 2, 3, 4]
flatMap()
[1, 2, 3, 4].flatMap(a => [a**2]); // [1, 4, 9, 16]
5.2. String.trimStart()和String.trimEnd()
去除字符串首尾空白字符
' hello'.trimStart() // 'hello'
'hello '.trimEnd() // 'hello'
5.3. String.prototype.matchAll
matchAll()
方法返回一個(gè)包含所有匹配正則表達(dá)式的結(jié)果及分組捕獲組的迭代器旨剥。
const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';
const array = [...str.matchAll(regexp)];
console.log(array[0]);
// expected output: Array ["test1", "e", "st1", "1"]
console.log(array[1]);
// expected output: Array ["test2", "e", "st2", "2"]
5.4. Symbol.prototype.description
用來獲取Symbol
字符串的描述
let sy = Symbol('hello world')
console.log(sy.description) // 'hello world'
5.5. Object.fromEntries()
Object.entries()
是將對(duì)象轉(zhuǎn)成一個(gè)自身可枚舉屬性的鍵值對(duì)數(shù)組。同樣浅缸,我們也可以通過 Object.fromEntries()
把鍵值對(duì)數(shù)組轉(zhuǎn)成了對(duì)象轨帜。
// 將數(shù)組轉(zhuǎn)成對(duì)象
const array = [['key 1', 'value 1'],['key 2', 'value 2']
Object.fromEntries(array) // { key 1: "value 1", key 2: "value 2"}
//將 Map 轉(zhuǎn)成對(duì)象
const map = new Map()
map.set('key 1', 'value 1')
map.set('key 2', 'value 2')
Object.fromEntries(map) // { key 1: "value 1", key 2: "value 2"}
5.6. 可選 Catch Binding
允許開發(fā)人員在catch
塊中,不使用error參數(shù)的情況下使用try/catch
// ES10 之前使用
try {
// some code
}
catch (err) {
// error handling code
}
// 現(xiàn)在使用ES10這樣的try / catch:
try {
// some code
}
catch {
// error handling code
}
6. ES11(ECMAScript 2020)
6.1. 私有屬性
使用#
修飾私有字段
class Person {
name
#age
constructor(name, age) {
this.name = name
this.#age = age
}
}
const person= new Person('danny', 22)
console.log(person.name) // danny
console.log(person.#age) // Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class
6.2. Nullish coalescing Operator(空值處理)
表達(dá)式在 ??
的左側(cè) 運(yùn)算符求值為undefined或null衩椒,返回其右側(cè)
let user = {
u1: 0,
u2: false,
u3: null,
u4: undefined
u5: '',
}
let u2 = user.u2 ?? '用戶2' // false
let u3 = user.u3 ?? '用戶3' // 用戶3
let u4 = user.u4 ?? '用戶4' // 用戶4
let u5 = user.u5 ?? '用戶5' // ''
6.3. 可選鏈(Optional chaining)
使用 ?.
檢測(cè)不確定的中間節(jié)點(diǎn)
let user = {}
let u1 = user.childer.name // TypeError: Cannot read property 'name' of undefined
let u2 = user.childer?.name // undefined
6.4. Promise.allSettled
該Promise.allSettled()
方法返回一個(gè)在所有給定的promise
都已經(jīng)fulfilled
或rejected
后的promise蚌父,并帶有一個(gè)對(duì)象數(shù)組,每個(gè)對(duì)象表示對(duì)應(yīng)的promise結(jié)果毛萌。
當(dāng)您有多個(gè)彼此不依賴的異步任務(wù)成功完成時(shí)苟弛,或者您總是想知道每個(gè)promise
的結(jié)果時(shí),通常使用它阁将。
相比之下膏秫,Promise.all()
更適合彼此相互依賴或者在其中任何一個(gè)reject
時(shí)立即結(jié)束。
const promises = [
fetch('/api-1'),
fetch('/api-2'),
fetch('/api-3'),
];
await Promise.allSettled(promises)
.then((results) => results
.forEach((result) => console.log(result.status)))
6.5. 動(dòng)態(tài)import
動(dòng)態(tài)導(dǎo)入hello模塊進(jìn)行使用做盅,import(路徑)的得到的是一個(gè)Promise對(duì)象缤削,使用then獲取成功的模塊。
// a.js
export const hello = () => {
alert('hello');
};
// b.js
const btn = document.querySelector('#btn');
btn.onclick = () => {
import('./a.js').then(module => {
module.hello();
});
};
6.6. BigInt
ES11 引入了新的數(shù)據(jù)類型 BigInt類型 大整型吹榴,進(jìn)行更大的數(shù)值運(yùn)算亭敢。
注意:大整型只能和大整型進(jìn)行運(yùn)算
// 使用方法:
// 1.在普通的整型數(shù)后加n
let n = 666n;
console.log(n, typeof n); //666n "bigint"
// 2.使用BigInt()函數(shù)
let n = 666;
console.log(BigInt(n)); // 666n
6.7. 絕對(duì)全局對(duì)象(globalThis)
字面意思為全局的this
, globalThis
始終指向全局對(duì)象(無論運(yùn)行環(huán)境node、瀏覽器等)
console.log(globalThis) //Window {window: Window, self: Window, document: document, name: "", location: Location, …}
7. ES12(ECMAScript2021)
7.1. replaceAll
返回一個(gè)全新的字符串图筹,所有符合匹配規(guī)則的字符都將被替換掉
const str = 'hello world';
str.replaceAll('o', 'b'); // "hellb wbrld"
7.2. Promise.any
Promise.any() 接收一個(gè)Promise可迭代對(duì)象帅刀,只要其中的一個(gè) promise 成功,就返回那個(gè)已經(jīng)成功的 promise 远剩。如果可迭代對(duì)象中沒有一個(gè) promise 成功(即所有的 promises 都失敗/拒絕)扣溺,就返回一個(gè)失敗的 promise
const promise1 = new Promise((resolve, reject) => reject('我是失敗的Promise_1'));
const promise2 = new Promise((resolve, reject) => reject('我是失敗的Promise_2'));
const promiseList = [promise1, promise2];
Promise.any(promiseList)
.then(values=>{
console.log(values);
})
.catch(e=>{
console.log(e);
}); // AggregateError: All promises were rejected
const promise3 = new Promise((resolve, reject) => reject('我是失敗的Promise_3'));
const promise4 = new Promise((resolve, reject) => resolve('我是成功的Promise_4'));
const promiseList1 = [promise3, promise4];
Promise.any(promiseList1)
.then(values=>{
console.log(values);
})
.catch(e=>{
console.log(e);
}); // 我是成功的Promise_4
7.3. WeakRefs
使用WeakRefs的Class類創(chuàng)建對(duì)對(duì)象的弱引用(對(duì)對(duì)象的弱引用是指當(dāng)該對(duì)象應(yīng)該被GC回收時(shí)不會(huì)阻止GC的回收行為)
7.4. 邏輯運(yùn)算符和賦值表達(dá)式
邏輯運(yùn)算符和賦值表達(dá)式,新特性結(jié)合了邏輯運(yùn)算符(&&瓜晤,||娇妓,??)和賦值表達(dá)式而JavaScript已存在的復(fù)合賦值運(yùn)算符有:
操作運(yùn)算符:+= -= *= /= %= **=
位操作運(yùn)算符:&= ^= |=
按位運(yùn)算符:<<= >>= >>>=
現(xiàn)有的的運(yùn)算符,其工作方式都可以如此來理解
表達(dá)式:a op= b
等同于:a = a op b
邏輯運(yùn)算符和其他的復(fù)合賦值運(yùn)算符工作方式不同
表達(dá)式:a op= b
等同于:a = a op (a = b)
a ||= b
//等價(jià)于
a = a || (a = b)
a &&= b
//等價(jià)于
a = a && (a = b)
a ??= b
//等價(jià)于
a = a ?? (a = b)
為什么不再是跟以前的運(yùn)算公式a = a op b一樣呢活鹰,而是采用a = a op (a = b)哈恰。因?yàn)楹笳弋?dāng)且僅當(dāng)a的值為false的時(shí)候才計(jì)算賦值,只有在必要的時(shí)候才執(zhí)行分配志群,而前者的表達(dá)式總是執(zhí)行賦值操作
7.5. 數(shù)字分隔符
數(shù)字分隔符着绷,可以在數(shù)字之間創(chuàng)建可視化分隔符,通過_下劃線來分割數(shù)字锌云,使數(shù)字更具可讀性
const money1 = 1_000_000_000;
//等價(jià)于
const money2 = 1000000000;
money1 === money2 // true