圍觀!我國第一個推進到瀏覽器標(biāo)準(zhǔn)的 ECMaScript 提案!
以下文章來源于前端很美 ,作者ginkgo6
在2022年6月22日,第123屆Ecma大會批準(zhǔn)了ECMAScript 2022語言規(guī)范。一起來看看ES13給我們帶來了哪些新特性吧。其中最后一個特性,是我國第一個推進到瀏覽器標(biāo)準(zhǔn)的EcmaScript提案。
1.私有屬性和私有方法
之前js中class的一個痛點就是沒有私有屬性,畢竟封裝是面向?qū)ο蟮娜筇匦裕瑳]有私有屬性如何實現(xiàn)封裝。盡管我們可以用很多方法去曲線實現(xiàn)私有屬性比如閉包proxy、weakmap、symbol等等,但是他們各自有各自的缺陷,下面的代碼演示其中以_作為命名約定的方式實現(xiàn)私有屬性的缺點。
class User {
constructor() {
// public 屬性
this.name = "Tom";
// private 屬性
this._lastName = "Brown";
}
getFullName(){
return `${this.name} ${this._lastName}`
}
}
const user = new User();
user.name
// "Tom"
user._lastName
// "Brown"
// no error thrown, we can access it from outside the class
在構(gòu)造函數(shù)中,我們定義了兩個字段,其中一個字段是以_開頭的, 這是一個命名約定用于將字段聲明為私有字段,但是當(dāng)我們在類外面訪問該字段時,并沒有引起報錯,原因是因為它只是一個命名規(guī)范而已。
現(xiàn)在在ES13中,我們可以用更簡單的方法聲明公共和私有字段,第一,我們不必在構(gòu)造函數(shù)中定義它們了,其次,我們可以通過在字段前面添加#號來定義一個真正的私有字段。
class User {
name = "Tom";
#lastName = "Brown"
getFullName(){
return `${this.name} ${this.#lastName}`
}
}
const user = new User();
user.name
// "Tom"
user.getFullName();
// "Tom Brown"
user.#lastName
// SyntaxError - cannot be accessed or modified from outside the class
有了這個特性,我們終于可以簡單輕松的定義一個真正的私有屬性或私有方法了。
2.私有屬性檢測
當(dāng)我們嘗試訪問對象上不存在的私有屬性時會報錯,所以就需要一種方法來檢測對象是否具有某私有屬性,此時,我們可以在class中使用in關(guān)鍵字來完成此工作。
class Person {
#name;
constructor(name) {
this.#name = name;
}
static check(obj) {
return #name in obj;
}
}
Person.check(new Person()), // true
當(dāng)然,你可能會發(fā)問對于具有相同名稱的私有屬性的類,in 關(guān)鍵字是否能正常工作,別擔(dān)心,請參考以下例子,User類和Person類具有相同的私有屬性name,in關(guān)鍵字可以正確的區(qū)分。
class User {
#name;
constructor(name) {
this.#name = name;
}
static check(obj) {
return #name in obj;
}
}
class Person {
#name;
constructor(name) {
this.#name = name;
}
static check(obj) {
return #name in obj;
}
}
User.check(new User()), // true
User.check(new Person()), // false
Person.check(new Person()), // true
Person.check(new User()), // false
3. 類靜態(tài)初始化塊(Class Static Block)
類在初始化的時候會執(zhí)行靜態(tài)初始化塊(Class Static Block),一個類可以擁有任意個靜態(tài)初始化塊,它們將會按照聲明的順序執(zhí)行。靜態(tài)初始塊內(nèi)還可以訪問父類的靜態(tài)屬性。
class Dictionary {
static words = [ "yes", "no", "maybe" ];
}
class Words extends Dictionary {
static englishWords = [];
static #localWord = 'ok';
// 第一個靜態(tài)初始化塊
static {
const words = super.words;
this.englishWords.push(...words);
}
// 第二個靜態(tài)初始化塊
static {
this.englishWords.push(this.#localWord);
}
}
console.log(Words.englishWords)
//輸出 -> ["yes", "no", "maybe", "ok"]
下面這個例子,我們還可以通過靜態(tài)初始化塊將私有屬性暴露出去。
let getClassPrivateField;
class Person {
#privateField;
constructor(value) {
this.#privateField = value;
}
static {
getClassPrivateField = (obj) => obj.#privateField;
}
}
getClassPrivateField(new Person('private value'));
4.Regexp Match Indices
之前 ECMAScript 中的 「RegExp.prototype.exec」 方法的返回值已經(jīng)提供了對于匹配的捕獲組 文本與對應(yīng)的捕獲組在正則表達式中的索引。盡管它已經(jīng)包含輸入字符串,模式匹配的索引以及包含任何已命名捕獲組的子字符串的group對象,但是對于復(fù)雜情況,此信息可能不足。
const fruits = 'Fruits: apple, banana, orange'
const regex = /(banana)/g;
const matchObj = regex.exec(fruits);
console.log(matchObj);
// [
// 'banana',
// 'banana',
// index: 15,
// input: 'Fruits: apple, banana, orange',
// groups: undefined
// ]
所以ES13通過新增/d修飾符,向匹配結(jié)果添加一個屬性 .indices,此屬性是一個索引數(shù)組,其中包含每個捕獲的子字符串的一對開始索引和結(jié)束索引。
const fruits = 'Fruits: apple, banana, orange'
const regex = /(banana)/gd;
const matchObj = regex.exec(fruits);
console.log(matchObj);
// [
// 'banana',
// 'banana',
// index: 15,
// indices:[
// [15, 21],
// [15, 21]
// ]
// input: 'Fruits: apple, banana, orange',
// groups: undefined
// ]
5.Await operator at the top-level
之前await關(guān)鍵詞只能在aysnc function里進行使用,想要在頂層使用await就必須要加個aysnc自執(zhí)行函數(shù),這樣十分的不方便, 所以ES13中,引入了可以直接在頂層使用Await關(guān)鍵字的特性。
動態(tài)加載模塊:
const strings = await import(`./example.mjs`); |
依賴回退:
let jQuery;
try {
jQuery = await import('https://cdn-a.com/jQuery');
} catch {
jQuery = await import('https://cdn-b.com/jQuery');
}
加載最快的資源
const resource = await Promise.any([
fetch('http://example1.com'),
fetch('http://example2.com'),
]);
6 .at()方法
之前,我們?nèi)绻胍@取一個數(shù)組的元素,如果是正序獲取一個元素,我們可以采取arr[0]這樣的方式, 但是如果我們要倒序訪問一個數(shù)組的元素,就需要采取arr[arr.length - 2]這樣的方式,數(shù)組的名稱arr我們寫了兩次,而且還要寫個length,這很不優(yōu)雅,復(fù)雜的情況下就更是難受。
const arr = [100,200,300,400]
arr[0] // 100
arr[arr.length - 2] // 300
arr.slice(-2)[0] // 300
為了解決這個問題, ES13引入了at()方法,無論正序還是倒序獲取元素都非常的優(yōu)雅,有了這個方法,我們可以在數(shù)組、字符串、TypedArray上通過索引值方便的獲取元素。
const arr = [100,200,300,400]
arr.at(0) // 100
arr.at(-2) // 300
const str = "ABCD"
str.at(-1) // 'D'
str.at(0) // 'A'
7.Object.hasOwn(obj, propKey)
之前我們?nèi)绻胍袛嗄硨ο笫欠窬哂心硨傩裕覀儠ㄟ^in和obj.hasOwnProperty,但是如果指定的屬性位于原型鏈中,“in”運算符也會返回true。所以之前要想判斷對象自身是否具有某屬性我們一般都通過obj.hasOwnProperty來判斷。
但是obj.hasOwnProperty也有自身的缺點:因為hasOwnProperty是不受保護的屬性,所以,人們可能會在對象上定義個自己的hasOwnProperty,如下所示,自定義的hasOwnProperty永遠返回false,這是一個坑。
const person = {
name: "Roman",
hasOwnProperty:()=> {
return false
}
}
person.hasOwnProperty('name'); // false
另一個問題是使用Object.create(null) 創(chuàng)建一個不繼承自 Object.prototype 的對象,使 hasOwnProperty 方法時會報錯。
Object.create(null).hasOwnProperty("name")
// Uncaught TypeError: Object.create(...).hasOwnProperty is not a function
所以,為了解決上面的問題,ES13引入了**Object.hasOwn(obj, propKey)**。用法如下所示:
const object = { name: "Mark" };
Object.hasOwn(object, "name"); // true
const object2 = Object.create({ name: "Roman" });
Object.hasOwn(object2, "name"); // false
Object.hasOwn(object2.__proto__, "name"); // true
const object3 = Object.create(null);
Object.hasOwn(object3, "name"); // false
8.Error Cause
Error Cause提案由阿里巴巴的「昭朗」同學(xué)負責(zé),是我國第一個成為瀏覽器標(biāo)準(zhǔn)的EcmaScript提案。
以前因為 Error Cause 沒有標(biāo)準(zhǔn)化的參數(shù)定義及官方實現(xiàn),所以容易丟失 error 的屬性或需要寫比較多的代碼自定義等,并且開發(fā)者工具也難以依賴于非語言特性的自定義方案。
try {
apiCallThatCanThrow();
} catch (err) {
throw new Error('New error message', { cause: err });
}
有了這個新特性,借助cause屬性,我們可以記下導(dǎo)致這個Error的前一個Error對象,錯誤對象就可以以一種簡單優(yōu)雅的方式鏈接起來。
9.總結(jié)
以上就是ES13的新特性,新特性會給js生態(tài)帶來更多好的東西,提高開發(fā)者的效率和體驗。
作者:ginkgo6
歡迎關(guān)注微信公眾號 :前端印象