1.類字段聲明
在 ES13 之前齐帚,類字段只能在構(gòu)造函數(shù)中聲明。與許多其他語(yǔ)言不同彼哼,我們不能在類的最外層范圍內(nèi)聲明或定義它們对妄。
class Car {
constructor() {
this.color = 'blue';
this.age = 2;
}
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2
ES13 消除了這個(gè)限制。現(xiàn)在我們可以編寫如下代碼:
class Car {
color = 'yellow';
age = 2;
}
const car = new Car();
console.log(car.color); // yellow
console.log(car.age); // 2
2.私有方法和字段
以前敢朱,不能在類中聲明私有成員剪菱。成員通常以下劃線 (_) 為前綴,表示它是私有的拴签,但仍然可以從類外部訪問和修改孝常。
class Person {
_firstName = 'Joseph';
_lastName = 'Stevens';
get name() {
return `${this._firstName} ${this._lastName}`;
}
}
const person = new Person();
console.log(person.name); // Joseph Stevens
// Members intended to be private can still be accessed
// from outside the class
console.log(person._firstName); // Joseph
console.log(person._lastName); // Stevens
// They can also be modified
person._firstName = 'Robert';
person._lastName = 'Becker';
console.log(person.name); // Robert Becker
使用 ES13,我們現(xiàn)在可以將私有字段和成員添加到類中蚓哩,方法是在其前面加上井號(hào) (#)构灸。試圖從類外部訪問它們會(huì)導(dǎo)致錯(cuò)誤:
class Person {
#firstName = 'Joseph';
#lastName = 'Stevens';
get name() {
return `${this.#firstName} ${this.#lastName}`;
}
}
const person = new Person();
console.log(person.name); // Joseph Stevens
// SyntaxError: Private field '#firstName' must be declared //in an enclosing class
console.log(person.#firstName);
console.log(person.#lastName);
請(qǐng)注意,這里拋出的錯(cuò)誤是語(yǔ)法錯(cuò)誤岸梨,發(fā)生在編譯時(shí)冻押,因此沒有部分代碼運(yùn)行。編譯器甚至不希望您嘗試從類外部訪問私有字段盛嘿,因此它假定您正在嘗試聲明一個(gè)。
3.頂層等待操作符
在 JavaScript 中括袒,await 運(yùn)算符用于暫停執(zhí)行次兆,直到 Promise 被解決(履行或拒絕)。
以前锹锰,我們只能在 async 函數(shù)中使用此運(yùn)算符 - 使用 async 關(guān)鍵字聲明的函數(shù)芥炭。我們無法在全局范圍內(nèi)這樣做。
function setTimeoutAsync(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}// SyntaxError: await is only valid in async functions
await setTimeoutAsync(3000);
使用 ES13恃慧,現(xiàn)在我們可以:
function setTimeoutAsync(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(111)
resolve();
}, timeout);
});
}
// Waits for timeout - no error thrown
await setTimeoutAsync(3000);
好處:
1.代碼更簡(jiǎn)練园蝠,不用多寫一層function。
2.在父級(jí)調(diào)用該子模塊時(shí)痢士,會(huì)根據(jù)await執(zhí)行同步命令彪薛,暫停父級(jí)執(zhí)行。
4.靜態(tài)類字段和靜態(tài)私有方法
我們現(xiàn)在可以在 ES13 中為類聲明靜態(tài)字段和靜態(tài)私有方法。靜態(tài)方法可以使用 this 關(guān)鍵字訪問類中的其他私有/公共靜態(tài)成員善延,實(shí)例方法可以使用 this.constructor 訪問它們少态。
class Person {
static #count = 0;
static getCount() {
return this.#count;
}
constructor() {
this.constructor.#incrementCount();
}
static #incrementCount() {
this.#count++;
}
}
const person1 = new Person();
const person2 = new Person();
console.log(Person.getCount()); // 2
5.類靜態(tài)塊
ES13 允許在創(chuàng)建類時(shí)定義只執(zhí)行一次的靜態(tài)塊。這類似于其他支持面向?qū)ο缶幊痰恼Z(yǔ)言(如 C# 和 Java)中的靜態(tài)構(gòu)造函數(shù)易遣。
一個(gè)類的類主體中可以有任意數(shù)量的靜態(tài) {} 初始化塊彼妻。它們將與任何交錯(cuò)的靜態(tài)字段初始值設(shè)定項(xiàng)一起按照聲明的順序執(zhí)行。我們可以在靜態(tài)塊中使用超屬性來訪問超類的屬性豆茫。
class Vehicle {
static defaultColor = 'blue';
}
class Car extends Vehicle {
static colors = [];
static {
this.colors.push(super.defaultColor, 'red');
}
static {
this.colors.push('green');
}
}
console.log(Car.colors); // [ 'blue', 'red', 'green' ]
6. 私有字段檢查
我們可以使用這個(gè)新特性來檢查
一個(gè)對(duì)象中是否有一個(gè)特定的私有字段侨歉,使用 in 運(yùn)算符。
class Car {
#color;
hasColor() {
return #color in this;
}
}
const car = new Car();
console.log(car.hasColor()); // true;
class Car {
#color;
hasColor() {
return #color in this;
}
}
class House {
#color;
hasColor() {
return #color in this;
}
}
const car = new Car();
const house = new House();
console.log(car.hasColor()); // true;
console.log(car.hasColor.call(house)); // false
console.log(house.hasColor()); // true
console.log(house.hasColor.call(car)); // false
7. at() 方法進(jìn)行索引
我們通常在 JavaScript 中使用方括號(hào) ([]) 來訪問數(shù)組的第 N 個(gè)元素揩魂,這通常是一個(gè)簡(jiǎn)單的過程幽邓。我們只訪問數(shù)組的 N - 1 屬性。
const arr = ['a', 'b', 'c', 'd'];
console.log(arr[1]); // b
但是肤京,如果我們想使用方括號(hào)訪問數(shù)組末尾的第 N 個(gè)項(xiàng)目颊艳,我們必須使用 arr.length - N 的索引。
const arr = ['a', 'b', 'c', 'd'];
// 1st element from the end
console.log(arr[arr.length - 1]); // d
// 2nd element from the end
console.log(arr[arr.length - 2]); // c
新的 at() 方法讓我們可以更簡(jiǎn)潔忘分、更有表現(xiàn)力地做到這一點(diǎn)棋枕。要訪問數(shù)組末尾的第 N 個(gè)元素,我們只需將負(fù)值 -N 傳遞給 at()妒峦。
const arr = ['a', 'b', 'c', 'd'];
// 1st element from the end
console.log(arr.at(-1)); // d
// 2nd element from the end
console.log(arr.at(-2)); // c
除了數(shù)組重斑,字符串和 TypedArray 對(duì)象現(xiàn)在也有 at() 方法。
const str = 'Coding Beauty';
console.log(str.at(-1)); // y
console.log(str.at(-2)); // t
const typedArray = new Uint8Array([16, 32, 48, 64]);
console.log(typedArray.at(-1)); // 64
console.log(typedArray.at(-2)); // 48
8.RegExp 匹配索引
這個(gè)新功能允許我們指定我們想要獲取給定字符串中 RegExp 對(duì)象匹配的開始和結(jié)束索引肯骇。
以前窥浪,我們只能在字符串中獲取正則表達(dá)式匹配的起始索引。
const str = 'sun and moon';
const regex = /and/;
const matchObj = regex.exec(str);
// [ 'and', index: 4, input: 'sun and moon', groups: undefined ]
console.log(matchObj);
我們現(xiàn)在可以指定一個(gè)d正則表達(dá)式標(biāo)志來獲取匹配開始和結(jié)束的兩個(gè)索引笛丙。
設(shè)置 d 標(biāo)志后漾脂,返回的對(duì)象將具有包含開始和結(jié)束索引的 indices 屬性。
const str = 'sun and moon';
const regex = /and/d;
const matchObj = regex.exec(str);
//[ 'and', index: 4, input: 'sun and moon', groups: undefined, indices: [ [ 4, 7 ], groups: undefined ]]
console.log(matchObj);
9. Object.hasOwn() 方法
在 JavaScript 中胚鸯,我們可以使用Object.prototype.hasOwnProperty() 方法來檢查對(duì)象是否具有給定的屬性骨稿。
class Car {
color = 'green';
age = 2;
}
const car = new Car();
console.log(car.hasOwnProperty('age')); // true
console.log(car.hasOwnProperty('name')); // false
但是這種方法存在一定的問題。一方面姜钳,
Object.prototype.hasOwnProperty() 方法不受保護(hù) - 它可以通過為類定義自定義hasOwnProperty() 方法來覆蓋坦冠,該方法可能具有Object.prototype.hasOwnProperty() 完全不同的行為。
class Car {
color = 'green';
age = 2;
hasOwnProperty() {
return false;
}
}
const car = new Car();
console.log(car.hasOwnProperty('age')); // false
console.log(car.hasOwnProperty('name')); // false
另一個(gè)問題是哥桥,對(duì)于使用 null 原型創(chuàng)建的對(duì)象(使用 Object.create(null))辙浑,嘗試對(duì)其調(diào)用此方法會(huì)導(dǎo)致錯(cuò)誤。
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
// TypeError: obj.hasOwnProperty is not a function
console.log(obj.hasOwnProperty('color'));
解決這些問題的一種方法是使用調(diào)用Object.prototype.hasOwnProperty Function 屬性上的 call() 方法拟糕,如下所示:
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () =>false;
console.log(Object.prototype.hasOwnProperty.call(obj, 'color')); // true
console.log(Object.prototype.hasOwnProperty.call(obj, 'name')); // false
這不是很方便判呕。我們可以編寫一個(gè)可重用的函數(shù)來避免重復(fù):
function objHasOwnProp(obj, propertyKey) {
return Object.prototype.hasOwnProperty.call(obj, propertyKey);
}
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;
console.log(objHasOwnProp(obj, 'color')); // true
console.log(objHasOwnProp(obj, 'name')); // false
不過沒有必要倦踢,因?yàn)槲覀兛梢允褂眯碌膬?nèi)置 Object.hasOwn() 方法。與我們的可重用函數(shù)一樣佛玄,它接受對(duì)象和屬性作為參數(shù)硼一,如果指定的屬性是對(duì)象的直接屬性,則返回 true梦抢。否則般贼,它返回 false。
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;
console.log(Object.hasOwn(obj, 'color')); // true
console.log(Object.hasOwn(obj, 'name')); // false
10. 錯(cuò)誤原因
錯(cuò)誤對(duì)象現(xiàn)在有一個(gè) cause 屬性奥吩,用于指定導(dǎo)致即將拋出的錯(cuò)誤的原始錯(cuò)誤哼蛆。這有助于為錯(cuò)誤添加額外的上下文信息并幫助診斷意外行為。我們可以通過在作為第二個(gè)參數(shù)傳遞給 Error() 構(gòu)造函數(shù)的對(duì)象上設(shè)置 cause 屬性來指定錯(cuò)誤的原因霞赫。
function userAction() {
try {
apiCallThatCanThrow();
}
catch (err) {
throw new Error('New error message', { cause: err });
}
}
try {
userAction();
} catch (err) {
console.log(err);
console.log(`Cause by: ${err.cause}`);
}
11.從最后一個(gè)數(shù)組查找
在 JavaScript 中腮介,我們已經(jīng)可以使用 Array find() 方法在數(shù)組中查找通過指定測(cè)試條件的元素。同樣端衰,我們可以使用 findIndex() 來查找此類元素的索引叠洗。雖然 find() 和 findIndex() 都從數(shù)組的第一個(gè)元素開始搜索,但在某些情況下旅东,最好從最后一個(gè)元素開始搜索灭抑。
在某些情況下,我們知道從最后一個(gè)元素中查找可能會(huì)獲得更好的性能抵代。例如腾节,這里我們?cè)噲D在數(shù)組中獲取值 等于 y 的項(xiàng)目。使用 find() 和 findIndex():
const letters = [ { value: 'v' }, { value: 'w' }, { value: 'x' },
{ value: 'y' }, { value: 'z' },];
const found = letters.find((item) => item.value === 'y');
const foundIndex = letters.findIndex((item) => item.value === 'y');
console.log(found); // { value: 'y' }
console.log(foundIndex); // 3
這行得通荤牍,但是由于目標(biāo)對(duì)象更靠近數(shù)組的尾部案腺,如果我們使用 findLast() 和 findLastIndex() 方法從末尾搜索數(shù)組,我們可以讓這個(gè)程序運(yùn)行得更快康吵。
const letters = [ { value: 'v' }, { value: 'w' }, { value: 'x' },
{ value: 'y' }, { value: 'z' },];
const found = letters.findLast((item) => item.value === 'y');
const foundIndex = letters.findLastIndex((item) => item.value === 'y');
console.log(found); // { value: 'y' }
console.log(foundIndex); // 3
另一個(gè)用例可能需要我們專門從末尾搜索數(shù)組以獲取正確的項(xiàng)目劈榨。例如,如果我們想在數(shù)字列表中找到最后一個(gè)偶數(shù)晦嵌, find() 和 findIndex() 會(huì)產(chǎn)生錯(cuò)誤的結(jié)果:
const nums = [7, 14, 3, 8, 10, 9];
// gives 14, instead of 10
const lastEven = nums.find((value) => value % 2 === 0);
// gives 1, instead of 4
const lastEvenIndex = nums.findIndex((value) => value % 2 === 0);
console.log(lastEven); // 14
console.log(lastEvenIndex); // 1
我們可以在調(diào)用 find() 和 findIndex() 之前調(diào)用數(shù)組的 reverse() 方法來反轉(zhuǎn)元素的順序鞋既。但是這種方法會(huì)導(dǎo)致數(shù)組不必要的突變,因?yàn)?reverse() 將數(shù)組的元素反轉(zhuǎn)到位耍铜。避免這種突變的唯一方法是制作整個(gè)數(shù)組的新副本,這可能會(huì)導(dǎo)致大型數(shù)組出現(xiàn)性能問題跌前。
此外棕兼, findIndex() 仍然無法在反轉(zhuǎn)數(shù)組上工作,因?yàn)榉崔D(zhuǎn)元素也意味著更改它們?cè)谠紨?shù)組中的索引抵乓。要獲得原始索引伴挚,我們需要執(zhí)行額外的計(jì)算靶衍,這意味著編寫更多代碼。
const nums = [7, 14, 3, 8, 10, 9];
const lastEven = nums.findLast((num) => num % 2 === 0);
const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0);
console.log(lastEven); // 10
console.log(lastEvenIndex); // 4
12.導(dǎo)入斷言
使用這種方式導(dǎo)入茎芋,我們就不需要手動(dòng)解析它了颅眶。
在 import…from… 后面加 assert { type: ‘json’ }
import json from './foo.json' assert { type: 'json' };
console.log(json.answer); // 42
1. String.replaceAll()
replaceAll()方法會(huì)返回一個(gè)全新的字符串,所有符合匹配規(guī)則的字符都將被替換掉田弥,替換規(guī)則可以是字符串或者正則表達(dá)式涛酗。
原始字符串保持不變。
let string = 'hello world, hello ES12'
string.replace(/hello/g,'hi') // hi world, hi ES12
string.replaceAll('hello','hi') // hi world, hi ES12
注意的是偷厦,replaceAll 在使用正則表達(dá)式的時(shí)候商叹,如果非全局匹配(/g),會(huì)拋出異常:
let string = 'hello world, hello ES12'
string.replaceAll(/hello/,'hi')
// Uncaught TypeError: String.prototype.replaceAll called with a non-global
2. 數(shù)字分隔符
數(shù)字分隔符可以在數(shù)字之間創(chuàng)建可視化分隔符只泼,通過 _下劃線來分割數(shù)字剖笙,使數(shù)字更具可讀性:
let budget = 1_000_000_000_000;
budget === 10 ** 12 // true
這個(gè)數(shù)值分隔符沒有指定間隔的位數(shù),也就是說请唱,可以每三位添加一個(gè)分隔符弥咪,也可以每一位、每?jī)晌皇蟆⒚克奈惶砑右粋€(gè)聚至。
123_00 === 12_300 // true
12345_00 === 123_4500 // true
小數(shù)和科學(xué)計(jì)數(shù)法也可以使用數(shù)值分隔符。
0.000_001 // 小數(shù)
1e10_000 // 科學(xué)計(jì)數(shù)法
數(shù)值分隔符有幾個(gè)使用注意點(diǎn)孽惰。
- 不能放在數(shù)值的最前面(leading)或最后面(trailing)晚岭。
- 不能兩個(gè)或兩個(gè)以上的分隔符連在一起。
- 小數(shù)點(diǎn)的前后不能有分隔符勋功。
- 科學(xué)計(jì)數(shù)法里面坦报,表示指數(shù)的e或E前后不能有分隔符
下面的寫法都會(huì)報(bào)錯(cuò)。
3_.141
3._141
1_e12
1e_12
123__456
_1464301
1464301_
3.Promise.any
方法接受一組 Promise 實(shí)例作為參數(shù)狂鞋,包裝成一個(gè)新的 Promise 實(shí)例返回片择。
const promise1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise1");
// reject("error promise1 ");
}, 3000);
});
};
const promise2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise2");
// reject("error promise2 ");
}, 1000);
});
};
const promise3 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise3");
// reject("error promise3 ");
}, 2000);
});
};
Promise.any([promise1(), promise2(), promise3()])
.then((first) => {
// 只要有一個(gè)請(qǐng)求成功 就會(huì)返回第一個(gè)請(qǐng)求成功的
console.log(first); // 會(huì)返回promise2
})
.catch((error) => {
// 所有三個(gè)全部請(qǐng)求失敗 才會(huì)來到這里
console.log("error", error);// err:AggregateError: All promises were rejected
console.log(error.message)// All promises were rejected
console.log(error.name) // AggregateError
console.log(err.errors) // ["error promise1", "error promise2", "error promise3"]
});
只要參數(shù)實(shí)例有一個(gè)變成fulfilled狀態(tài),包裝實(shí)例就會(huì)變成fulfilled狀態(tài)骚揍;如果所有參數(shù)實(shí)例都變成rejected狀態(tài)字管,包裝實(shí)例就會(huì)變成rejected狀態(tài)。
即:只要其中的一個(gè) promise 成功信不,就返回那個(gè)已經(jīng)成功的 promise 如果可迭代對(duì)象中沒有一個(gè) promise 成功(即所有的 promises 都失敗/拒絕)嘲叔,就返回一個(gè)失敗的 promise 和 AggregateError 類型的實(shí)例,它是 Error 的一個(gè)子類抽活,用于把單一的錯(cuò)誤集合在一起
Promise.any()跟Promise.race()方法很像硫戈,只有一點(diǎn)不同,就是Promise.any()不會(huì)因?yàn)槟硞€(gè) Promise 變成rejected狀態(tài)而結(jié)束下硕,必須等到所有參數(shù) Promise 變成rejected狀態(tài)才會(huì)結(jié)束丁逝。
4.邏輯運(yùn)算符和賦值表達(dá)式(&&=汁胆,||=,??=)
&&=
邏輯與賦值 x &&= y等效于:
x && (x = y);
上面的意思是霜幼,當(dāng)x為真時(shí)嫩码,x=y。具體請(qǐng)看下面的示例:
let a = 1;
let b = 0;
a &&= 2;
console.log(a); // 2
b &&= 2;
console.log(b); // 0
||=
邏輯或賦值(x ||= y)運(yùn)算僅在 x 為false時(shí)賦值罪既。
x ||= y 等同于:x || (x = y);
const a = { duration: 50, title: '' };
a.duration ||= 10;
console.log(a.duration); // 50
a.title ||= 'title is empty.';
console.log(a.title); // "title is empty"
??=
邏輯空賦值運(yùn)算符 (x ??= y) 僅在 x 是 null 或 undefined 時(shí)對(duì)其賦值铸题。
const a = { duration: 50 };
a.duration ??= 10;
console.log(a.duration); // 50
a.speed ??= 25;
console.log(a.speed); // 25
5.FinalizationRegistry
FinalizationRegistry 提供了這樣的一種方法:當(dāng)一個(gè)在注冊(cè)表中注冊(cè)的對(duì)象被回收時(shí),請(qǐng)求在某個(gè)時(shí)間點(diǎn)上調(diào)用一個(gè)清理回調(diào)
你可以通過調(diào)用register方法萝衩,注冊(cè)任何你想要清理回調(diào)的對(duì)象回挽,傳入該對(duì)象和所含的值
let obj = { name: "why", age: 18 }
let info = { name: "kobe", age: 30 }
const finalRegistry = new FinalizationRegistry((value) => {
console.log("某一個(gè)對(duì)象被回收了:", value)
})
finalRegistry.register(obj, "why")
finalRegistry.register(info, "kobe")
// obj = null
info = null
6.WeakRefs
新的類 WeakRefs。允許創(chuàng)建對(duì)象的弱引用猩谊。這樣就能夠在跟蹤現(xiàn)有對(duì)象時(shí)不會(huì)阻止對(duì)其進(jìn)行垃圾回收千劈。對(duì)于緩存和對(duì)象映射非常有用。
必須用 new關(guān)鍵字創(chuàng)建新的 WeakRef牌捷,并把某些對(duì)象作為參數(shù)放入括號(hào)中墙牌。當(dāng)你想讀取引用(被引用的對(duì)象)時(shí),可以通過在弱引用上調(diào)用 deref() 來實(shí)現(xiàn)暗甥。
如果我們默認(rèn)將一個(gè)對(duì)象賦值給另外一個(gè)引用喜滨,那么這個(gè)引用是一個(gè)強(qiáng)引用
如果我們希望是一個(gè)弱引用的話,可以使用WeakRef
let info = { name: "why", age: 18 }
let obj = new WeakRef(info)
let obj2 = new WeakRef(info)
const finalRegistry = new FinalizationRegistry(() => {
console.log("對(duì)象被回收~")
})
finalRegistry.register(info, "info")
setTimeout(() => {
info = null
}, 2000)
setTimeout(() => {
console.log(obj.deref().name, obj.deref().age)
}, 4000)
7.Intl.ListFormat
Intl.ListFormat 用來處理和多語(yǔ)言相關(guān)的對(duì)象格式化操作
Intl.ListFormat 參數(shù)/用法
new Intl.ListFormat([locales[, options]])
輸出處理過后的字符串
示例
//不允許存在數(shù)字,如有空格撤防,不會(huì)忽略空格
let strArr = ["xiaoming", "小明", "小紅", "XXMM"];
let EnForm = new Intl.ListFormat("en",{
localeMatcher:'lookup',
style:'short',
type:'disjunction'
}).format(strArr);
let cnForm = new Intl.ListFormat("zh-cn",{
localeMatcher:'lookup',
style:'short',
type:'disjunction'
}).format(strArr);
// lookup/best fit + long + conjunction 輸出:
// console.log("en", EnForm); // xiaoming, 小明, 小紅, and XXMM
// console.log("cn", cnForm); // xiaoming虽风、小明、小紅和XXMM
// lookup/best fit + short/long + disjunction 輸出:
// console.log("en", EnForm); // xiaoming, 小明, 小紅, or XXMM
// console.log("cn", cnForm); // xiaoming寄月、小明辜膝、小紅和XXMM
// lookup/best fit + short + conjunction 輸出:
// console.log("en", EnForm); // xiaoming, 小明, 小紅, & XXMM
// console.log("cn", cnForm); // xiaoming、小明漾肮、小紅和XXMM
// lookup/best fit + narrow + unit 輸出:
// console.log("en", EnForm); // xiaoming 小明 小紅 XXMM
// console.log("cn", cnForm); // xiaoming小明小紅XXMM
8. Intl.DateTimeFormat() 是什么厂抖?
可以用來處理多語(yǔ)言下的時(shí)間日期格式化函數(shù)。與 moment.js 時(shí)間插件相似
Intl.DateTimeFormat 參數(shù)/用法
new Intl.DateTimeFormat([locales[, options]])
示例
let date = new Date(); //獲取本機(jī)當(dāng)前時(shí)間
// 粗暴用法 獲取 年月日+時(shí)間
let dateShort = { timeStyle: "medium", dateStyle: "short" };
let dateMedium = { timeStyle: "medium", dateStyle: "medium" };
console.log(new Intl.DateTimeFormat('zh-cn',dateShort).format(date)); // 2022/8/5 15:27:17
console.log(new Intl.DateTimeFormat('zh-cn',dateMedium).format(date)); // 2022年8月5日 15:27:28
// 精確用法 獲取 公元+星期+年月日+時(shí)間
// 不傳克懊,取默認(rèn)的時(shí)間格式
console.log(new Intl.DateTimeFormat().format(date)); // 2022/8/5
let options1 = {
year: "numeric",
month: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
hour12: false, //是否為 12 小時(shí)制
}
console.log(new Intl.DateTimeFormat("de-DE", options1).format(date)); // de-DE(德語(yǔ)) Freitag, 5. August 2022
let options2 = {
era: "long", // 公元 locales如果為中文忱辅,切換任何參數(shù)都是公元,反之谭溉,才會(huì)有長(zhǎng)短顯示的區(qū)別
weekday: "long", // 星期幾
year: "numeric",
month: "numeric", // long 打印: 5. August 2022 um 14:31:44, short 打忧蕉:5. Aug. 2022, 14:32:37, narrow 打印:5. A 2022, 14:35:58
day: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
hour12: false,
};
console.log(new Intl.DateTimeFormat("zh-cn", options2).format(date)); // 公元2022年8月5日星期五 15:31:32
let options3 = {
timeStyle: "medium",
dateStyle: "short",
};
console.log(new Intl.DateTimeFormat("zh-cn", options3).format(date)); // 2022/8/5 14:27:59
9. Intl.RelativeTimeFormat()
處理時(shí)間格式扮念,轉(zhuǎn)換為昨天/前天/一天前/季度等
Intl.RelativeTimeFormat() 參數(shù)/用法
new Intl.RelativeTimeFormat([locales[, options]])
const tf = new Intl.RelativeTimeFormat(“zh-cn”);
console.log( tf.format(-10, “year”) );
// output :: 10年前
示例
// options 不寫表示默認(rèn)項(xiàng)
const tf = new Intl.RelativeTimeFormat("zh-cn");
// output :: 10年前
console.log(tf.format(-10, "year"));
// output :: 5個(gè)月前
console.log(tf.format(-5, "month"));
// output :: 2個(gè)季度后
console.log(tf.format(2, "quarter"));
// output :: 2周后
console.log(tf.format(2, "week"));
// output :: 2天前
console.log(tf.format(-2, "day"));
// output :: 8小時(shí)后
console.log(tf.format(8, "hour"));
// output :: 15分鐘前
console.log(tf.format(-15, "minute"));
// output :: 2秒鐘后
console.log(tf.format(2, "second"));
1.空值合并運(yùn)算符
空值合并操作符( ?? )是一個(gè)邏輯操作符损搬,當(dāng)左側(cè)的操作數(shù)為 null或者undefined時(shí),返回其右側(cè)操作數(shù),否則返回左側(cè)操作數(shù)场躯。
const foo = undefined ?? "foo"
const bar = null ?? "bar"
console.log(foo) // foo
console.log(bar) // bar
與邏輯或操作符(||)不同,邏輯或操作符會(huì)在左側(cè)操作數(shù)為假值時(shí)返回右側(cè)操作數(shù)旅挤。也就是說踢关,如果使用 || 來為某些變量設(shè)置默認(rèn)值,可能會(huì)遇到意料之外的行為粘茄。比如為假值(例如'',0,NaN,false)時(shí)签舞。見下面的例子
const foo = "" ?? 'default string';
const foo2 = "" || 'default string';
console.log(foo); // ""
console.log(foo2); // "default string"
const baz = 0 ?? 42;
const baz2 = 0 || 42;
console.log(baz); // 0
console.log(baz2); // 42
2.可選鏈
可選鏈操作符( ?. )允許讀取位于連接對(duì)象鏈深處的屬性的值,而不必明確驗(yàn)證鏈中的每個(gè)引用是否有效柒瓣。?. 操作符的功能類似于 . 鏈?zhǔn)讲僮鞣宕睿煌幵谟冢谝脼?null 或者 undefined 的情況下不會(huì)引起錯(cuò)誤芙贫,該表達(dá)式短路返回值是 undefined搂鲫。與函數(shù)調(diào)用一起使用時(shí),如果給定的函數(shù)不存在磺平,則返回 undefined魂仍。
當(dāng)嘗試訪問可能不存在的對(duì)象屬性時(shí),可選鏈操作符將會(huì)使表達(dá)式更短拣挪、更簡(jiǎn)明擦酌。在探索一個(gè)對(duì)象的內(nèi)容時(shí),如果不能確定哪些屬性必定存在菠劝,可選鏈操作符也是很有幫助的赊舶。
const user = {
address: {
street: 'xx街道',
getNum() {
return '80號(hào)'
}
}
}
在之前的語(yǔ)法中,想獲取到深層屬性或方法赶诊,不得不做前置校驗(yàn)笼平,否則很容易命中 Uncaught TypeError: Cannot read property... 這種錯(cuò)誤,這極有可能讓你整個(gè)應(yīng)用掛掉甫何。
const street = user && user.address && user.address.street
const num = user && user.address && user.address.getNum && user.address.getNum()
console.log(street, num)
用了 Optional Chaining 出吹,上面代碼會(huì)變成
const street2 = user?.address?.street
const num2 = user?.address?.getNum?.()
console.log(street2, num2)
常見用法
// 對(duì)象中使用
let obj = {
name: "jimmy",
age: "18",
};
let property = "age";
let name = obj?.name;
let age = obj?.age;
let ages = obj?.[property];
let sex = obj?.sex;
console.log(name); // jimmy
console.log(age); // 18
console.log(ages); // 18
console.log(sex); // undefined
// 數(shù)組中使用
let arr = [1,2,2];
let arrayItem = arr?.[42]; // undefined
// 函數(shù)中使用
let obj = {
func: function () {
console.log("I am func");
},
};
obj?.func(); // I am func
與空值合并操作符一起使用
let customer = {
name: "jimmy",
details: { age: 18 }
};
let customerCity = customer?.city ?? "成都";
console.log(customerCity); // "成都"
注意點(diǎn):可選鏈不能用于賦值
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
3.globalThis
在以前,從不同的 JavaScript 環(huán)境中獲取全局對(duì)象需要不同的語(yǔ)句辙喂。在 Web 中捶牢,可以通過 window、self 取到全局對(duì)象巍耗,在 Node.js 中秋麸,它們都無法獲取,必須使用 global炬太。
在松散模式下灸蟆,可以在函數(shù)中返回 this 來獲取全局對(duì)象,但是在嚴(yán)格模式和模塊環(huán)境下亲族,this 會(huì)返回 undefined炒考。
以前想要獲取全局對(duì)象可缚,可通過一個(gè)全局函數(shù)
const getGlobal = () => {
if (typeof self !== 'undefined') {
return self
}
if (typeof window !== 'undefined') {
return window
}
if (typeof global !== 'undefined') {
return global
}
throw new Error('無法找到全局對(duì)象')
}
const globals = getGlobal()
console.log(globals)
現(xiàn)在globalThis 提供了一個(gè)標(biāo)準(zhǔn)的方式來獲取不同環(huán)境下的全局 this 對(duì)象(也就是全局對(duì)象自身)。不像 window 或者 self 這些屬性斋枢,它確绷泵遥可以在有無窗口的各種環(huán)境下正常工作。所以瓤帚,你可以安心的使用 globalThis描姚,不必?fù)?dān)心它的運(yùn)行環(huán)境。
4.BigInt
BigInt 是一種內(nèi)置對(duì)象绊寻,它提供了一種方法來表示大于 2的53次方 的整數(shù)。這原本是 Javascript中可以用 Number 表示的最大數(shù)字擎颖。BigInt 可以表示任意大的整數(shù)榛斯。
使用 BigInt 有兩種方式:
方式一:數(shù)字后面增加n
const bigInt = 9007199254740993n
console.log(bigInt)
console.log(typeof bigInt) // bigint
// `BigInt` 和 [`Number`]不是嚴(yán)格相等的,但是寬松相等的搂捧。
console.log(1n == 1) // true
console.log(1n === 1) // false
// `Number` 和 `BigInt` 可以進(jìn)行比較驮俗。
1n < 2 // true
2n > 1 // true
方式二:使用 BigInt 函數(shù)
const bigIntNum = BigInt(9007199254740993)
console.log(bigIntNum)
運(yùn)算
let number = BigInt(2);
let a = number + 2n;
let b = number * 10n;
let c = number - 10n;
console.log(a);// 4n
console.log(b); // 20n
console.log(c);// -8n
注意點(diǎn)
BigInt不能用于 [Math] 對(duì)象中的方法;不能和任何 [Number] 實(shí)例混合運(yùn)算允跑,兩者必須轉(zhuǎn)換成同一種類型王凑。在兩種類型來回轉(zhuǎn)換時(shí)要小心,因?yàn)?BigInt 變量在轉(zhuǎn)換成 [Number] 變量時(shí)可能會(huì)丟失精度聋丝。
5.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]); // ["test1", "e", "st1", "1"]
console.log(array[1]); // ["test2", "e", "st2", "2"]
6.Promise.allSettled()
我們都知道 Promise.all() 具有并發(fā)執(zhí)行異步任務(wù)的能力。但它的最大問題就是如果其中某個(gè)任務(wù)出現(xiàn)異常(reject)弱睦,所有任務(wù)都會(huì)掛掉百姓,Promise直接進(jìn)入reject 狀態(tài)。
場(chǎng)景:現(xiàn)在頁(yè)面上有三個(gè)請(qǐng)求况木,分別請(qǐng)求不同的數(shù)據(jù)垒拢,如果一個(gè)接口服務(wù)異常,整個(gè)都是失敗的火惊,都無法渲染出數(shù)據(jù),我們需要一種機(jī)制求类,如果并發(fā)任務(wù)中,無論一個(gè)任務(wù)正骋倌停或者異常尸疆,都會(huì)返回對(duì)應(yīng)的的狀態(tài),這就是Promise.allSettled的作用
const promise1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise1");
// reject("error promise1 ");
}, 3000);
});
};
const promise2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise2");
// reject("error promise2 ");
}, 1000);
});
};
const promise3 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("promise3");
reject("error promise3 ");
}, 2000);
});
};
// Promise.all 會(huì)走到catch里面
Promise.all([promise1(), promise2(), promise3()])
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log("error", error); // error promise3
});
// Promise.allSettled 不管有沒有錯(cuò)誤,三個(gè)的狀態(tài)都會(huì)返回
Promise.allSettled([promise1(), promise2(), promise3()])
.then((res) => {
console.log(res);
// 打印結(jié)果
// [
// {status: 'fulfilled', value: 'promise1'},
// {status: 'fulfilled',value: 'promise2'},
// {status: 'rejected', reason: 'error promise3 '}
// ]
})
.catch((error) => {
console.log("error", error);
});
7.Dynamic Import(按需 import)
import()可以在需要的時(shí)候寿弱,再加載某個(gè)模塊犯眠。
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
上面代碼中,import()方法放在click事件的監(jiān)聽函數(shù)之中症革,只有用戶點(diǎn)擊了按鈕阔逼,才會(huì)加載這個(gè)模塊。
1.Object.fromEntries()
方法 Object.fromEntries() 把鍵值對(duì)列表轉(zhuǎn)換為一個(gè)對(duì)象地沮,這個(gè)方法是和Object.entries() 相對(duì)的。
Object.fromEntries([
['foo', 1],
['bar', 2]
])
// {foo: 1, bar: 2}
案例1:Object 轉(zhuǎn)換操作
const obj = {
name: 'jimmy',
age: 18
}
const entries = Object.entries(obj)
console.log(entries)
// [Array(2), Array(2)]
const fromEntries = Object.fromEntries(entries)
console.log(fromEntries)
// {name: "jimmy", age: 18}
案例2:Map 轉(zhuǎn) Object
const map = new Map()
map.set('name', 'jimmy')
map.set('age', 18)
console.log(map) // {'name' => 'jimmy', 'age' => 18}
const obj = Object.fromEntries(map)
console.log(obj)
// {name: "jimmy", age: 18}
案例3:過濾
course表示所有課程羡亩,想請(qǐng)求課程分?jǐn)?shù)大于80的課程組成的對(duì)象:
const course = {
math: 80,
english: 85,
chinese: 90
}
const res = Object.entries(course).filter(([key, val]) => val > 80)
console.log(res) // [ [ 'english', 85 ], [ 'chinese', 90 ] ]
console.log(Object.fromEntries(res)) // { english: 85, chinese: 90 }
案例4:url的search參數(shù)轉(zhuǎn)換
// let url = "https://www.baidu.com?name=jimmy&age=18&height=1.88"
// queryString 為 window.location.search
const queryString = "?name=jimmy&age=18&height=1.88";
const queryParams = new URLSearchParams(queryString);
const paramObj = Object.fromEntries(queryParams);
console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }
console.log([...queryParams.entries()]);// [ ['name', 'jimmy'], ['age', '18'], ['height', '1.88']]
2.Array.prototype.flat()
語(yǔ)法
let newArray = arr.flat([depth])
depth 可選
指定要提取嵌套數(shù)組的結(jié)構(gòu)深度摩疑,默認(rèn)值為 1懦胞。
示例
flat() 方法會(huì)按照一個(gè)可指定的深度遞歸遍歷數(shù)組粉渠,并將所有元素與遍歷到的子數(shù)組中的元素合并為一個(gè)新數(shù)組返回昧绣。
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat()); // [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2)); // [0, 1, 2, [3, 4]]
//使用 Infinity仓犬,可展開任意深度的嵌套數(shù)組
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// `flat()` 方法會(huì)移除數(shù)組中的空項(xiàng):
var arr5 = [1, 2, , 4, 5];
arr5.flat(); // [1, 2, 4, 5]
3.Array.prototype.flatMap()
flatMap() 方法首先使用映射函數(shù)映射每個(gè)元素挠蛉,然后將結(jié)果壓縮成一個(gè)新數(shù)組也糊。從方法的名字上也可以看出來它包含兩部分功能一個(gè)是 map垛吗,一個(gè)是 flat(深度為1)残腌。
var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {
// 返回新數(shù)組的元素
}[, thisArg])
callback
可以生成一個(gè)新數(shù)組中的元素的函數(shù)瓦灶,可以傳入三個(gè)參數(shù):
currentValue:當(dāng)前正在數(shù)組中處理的元素
index:可選 數(shù)組中正在處理的當(dāng)前元素的索引鸠删。
array:可選 被調(diào)用的 map 數(shù)組
thisArg可選
執(zhí)行 callback 函數(shù)時(shí) 使用的this 值。
示例
const numbers = [1, 2, 3]
numbers.map(x => [x * 2]) // [[2], [4], [6]]
numbers.flatMap(x => [x * 2]) // [2, 4, 6]
這個(gè)示例可以簡(jiǎn)單對(duì)比下 map 和 flatMap 的區(qū)別贼陶。當(dāng)然還可以看下下面的示例:
let arr = ['今天天氣不錯(cuò)', '', '早上好']
arr.map(s => s.split(''))
// [["今", "天", "天", "氣", "不", "錯(cuò)"],[""],["早", "上", "好"]]
arr.flatMap(s => s.split(''))
// ["今", "天", "天", "氣", "不", "錯(cuò)", "", "早", "上", "好"]
flatMap 方法與 map 方法和深度depth為1的 flat 幾乎相同.
4.String.prototype.trimStart()
trimStart() 方法從字符串的開頭刪除空格刃泡,trimLeft()是此方法的別名。
let str = ' foo '
console.log(str.length) // 8
str = str.trimStart() // 或str.trimLeft()
console.log(str.length) // 5
5.String.prototype.trimEnd()
trimEnd() 方法從一個(gè)字符串的右端移除空白字符碉怔,trimRight 是 trimEnd 的別名烘贴。
let str = ' foo '
console.log(str.length) // 8
str = str.trimEnd() // 或str.trimRight()
console.log(str.length) // 6
6.可選的Catch Binding
在 ES10 之前我們都是這樣捕獲異常的:
try {
// tryCode
} catch (err) {
// catchCode
}
在這里 err 是必須的參數(shù),在 ES10 可以省略這個(gè)參數(shù):
try {
console.log('Foobar')
} catch {
console.error('Bar')
}
應(yīng)用
驗(yàn)證參數(shù)是否為json格式
這個(gè)需求我們只需要返回true或false撮胧,并不關(guān)心catch的參數(shù)桨踪。
const validJSON = json => {
try {
JSON.parse(json)
return true
} catch {
return false
}
}
7.Symbol.prototype.description
我們知道,Symbol 的描述只被存儲(chǔ)在內(nèi)部的 Description 芹啥,沒有直接對(duì)外暴露锻离,我們只有調(diào)用 Symbol 的 toString() 時(shí)才可以讀取這個(gè)屬性:
const name = Symbol('es')
console.log(name.toString()) // Symbol(es)
console.log(name) // Symbol(es)
console.log(name === 'Symbol(es)') // false
console.log(name.toString() === 'Symbol(es)') // true
現(xiàn)在可以通過 description 方法獲取 Symbol 的描述:
const name = Symbol('es')
console.log(name.description) // es
name.description = "es2" // 只讀屬性 并不能修改描述符
console.log(name.description === 'es') // true
// 如果沒有描述符 輸出undefined
const s2 = Symbol()
console.log(s2.description) // undefined
8.JSON.stringify() 增強(qiáng)能力
JSON.stringify 在 ES10 修復(fù)了對(duì)于一些超出范圍的 Unicode 展示錯(cuò)誤的問題。因?yàn)?JSON 都是被編碼成 UTF-8叁征,所以遇到 0xD800–0xDFFF 之內(nèi)的字符會(huì)因?yàn)闊o法編碼成 UTF-8 進(jìn)而導(dǎo)致顯示錯(cuò)誤纳账。在 ES10 它會(huì)用轉(zhuǎn)義字符的方式來處理這部分字符而非編碼的方式,這樣就會(huì)正常顯示了捺疼。
// \uD83D\uDE0E emoji 多字節(jié)的一個(gè)字符
console.log(JSON.stringify('\uD83D\uDE0E')) // 打印出笑臉
// 如果我們只去其中的一部分 \uD83D 這其實(shí)是個(gè)無效的字符串
// 之前的版本 疏虫,這些字符將替換為特殊字符,而現(xiàn)在將未配對(duì)的代理代碼點(diǎn)表示為JSON轉(zhuǎn)義序列
console.log(JSON.stringify('\uD83D')) // "\ud83d"
9.修訂 Function.prototype.toString()
以前函數(shù)的toString方法來自O(shè)bject.prototype.toString(),現(xiàn)在的 Function.prototype.toString() 方法返回一個(gè)表示當(dāng)前函數(shù)源代碼的字符串。以前只會(huì)返回這個(gè)函數(shù)卧秘,不包含注釋呢袱、空格等。
function foo() {
// es10新特性
console.log('imooc')
}
console.log(foo.toString())
// 打印如下
// function foo() {
// // es10新特性
// console.log("imooc");
// }
將返回注釋翅敌、空格和語(yǔ)法等詳細(xì)信息羞福。