JavaScript在持續(xù)發(fā)展,近期ECMAScript 14中發(fā)布添加了一批新功能,讓我們一起來探索一下今年對JavaScript開發(fā)人員的新功能。時間的車輪又過去了一年,隨之而來的是JavaScript的新官方版本:ECMAScript 2023,也被稱為ECMAScript 14。今年的改進包括對數(shù)組的添加和對ECMAScript文件中shebang的支持,以及對弱集合的符號鍵的擴展。這些變化主要是對語言的細化改進,而不是什么重大的變革。然而,這些改變的綜合效果是繼續(xù)推進語言的發(fā)展。下面是JavaScript在2023年的新功能概覽演示。
理解規(guī)范
ECMAScript規(guī)范是一份令人印象深刻的文檔,既是開發(fā)人員和教育者的基本參考,也是JavaScript引擎實現(xiàn)者的官方技術(shù)規(guī)范。這是一個相當(dāng)平衡的過程,規(guī)范處理得很好。由于包含了大量的信息,它作為語言的用戶指南可能有些繁瑣。
關(guān)于規(guī)范的另一個要了解的事情是,它實際上是一個活動的文檔,在語言在實際應(yīng)用中使用時會不斷發(fā)展。通常情況下,新功能在被用戶社區(qū)非正式接受后才會被添加到官方規(guī)范中。例如,今年的shebang語法就是一個例子。一旦一個功能被規(guī)范所編碼和標(biāo)準(zhǔn)化,規(guī)范就成為進一步創(chuàng)新該功能的新穩(wěn)定基礎(chǔ)。
有時,ECMAScript規(guī)范引入了開創(chuàng)性的想法。一個例子是采用了受C#影響的/語法。async/await 作為一種語言,JavaScript已經(jīng)從復(fù)制粘貼的鼠標(biāo)懸停效果的時代飛躍而來。ECMAScript規(guī)范過程在這一演變中起到了巨大的作用。
現(xiàn)在,讓我們來看看在2023年引入的JavaScript的新功能。
數(shù)組原型對象的toSorted方法
讓我們從新的數(shù)組方法toSorted()開始。toSorted()具有與sort()相同的簽名,但它創(chuàng)建一個新的數(shù)組,而不是在原數(shù)組上進行操作。下面是列表1中的新數(shù)組方法Array.prototype.sort()與toSorted()的對比。
列表1. sort()與toSorted()的對比
let arr = [5,4,2,3,1]
arr === arr.sort(); // true - [1, 2, 3, 4, 5]
arr === arr.toSorted(); // false - [1, 2, 3, 4, 5]
toSorted()和sort()一樣,也接受一個可選的參數(shù),即比較函數(shù)。例如,我們可以使用toSorted()創(chuàng)建一個按降序排列的新數(shù)組,如列表2所示。
列表2. 使用比較函數(shù)
const numbers = [10, 5, 2, 7, 3, 9, 1, 6, 4];
const sortedNumbers = numbers.toSorted((a, b) => {
return b - a;
});
console.log(sortedNumbers); // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
還需要注意的是,toSorted()也可以應(yīng)用于對象數(shù)組。在這種情況下,您必須提供一個使用對象上的數(shù)據(jù)的比較函數(shù),因為對象沒有自然的排序方式。您可以在列表3中看到一個示例。
列表3. 使用對象的toSorted()
// Comparing objects
const objects = [{ name: "John", age: 30 }, { name: "Jane", age: 25 }, { name: "Bill", age: 40 }, { name: "Mary", age: 20 }];
const sortedObjects = objects.toSorted((a, b) => {
return a.name.localeCompare(b.name);
});
console.log(sortedObjects);
//[{"name":"Bill","age":40},{"name":"Jane","age":25},{"name":"John","age":30},{"name":"Mary","age":20}]
與toSorted()和sort()類似,toReversed()是reverse()的復(fù)制版本。列表4中有一些使用toReversed()的快速示例,包括將其應(yīng)用于帶有比較函數(shù)的對象。
列表4. 使用toReversed()
["a","b","c","d","e"].toReversed(); // ['e', 'd', 'c', 'b', 'a']
Array.prototype.with新的with()方法允許您根據(jù)索引修改單個元素,并返回一個新的數(shù)組。因此,如果您知道索引和新值,這個方法非常方便。請注意,with()是set()的復(fù)制伴侶。列表5給出了一個簡單的示例。
列表5. 使用with()和set()方法的示例
const arr4 = ["I", "am", "the", "Walrus"];
// Replace the string "Walrus" with "Octopus".
const newArr4 = arr4.with(3, "Ape Man");
console.log(newArr4);
Array.prototype.findLast方法允許您從數(shù)組中獲取最后一個匹配元素的實例。如果沒有找到匹配的元素,則返回undefined。在列表6中給出了一個簡單的示例,我們從數(shù)組中獲取最后一個偶數(shù)。
列表6. 使用findLast()方法的示例
onst arr = [54, 34, 55, 75, 98, 77];
const lastEvenIndex = arr.findLast((element) => {
return element % 2 === 0;
});
console.log(lastEvenIndex); // 98
findLast()還支持傳入一個" "來設(shè)置上下文。也就是說,第二個參數(shù)將告訴第一個參數(shù)函數(shù)關(guān)鍵字將指向什么。您可以在列表7中看到這一點,在列表7中,我們使用一個自定義對象來查找第一個可以被5.thisArgthis整除的元素。
列表7.使用thisArg
const arr6 = [54, 34, 55, 75, 98, 77];
const myObject = {testCase: 5};
const lastEvenIndex = arr5.findLast((element) => {
return element % myObject.testCase === 0;
}, myObject);
console.log(lastEvenIndex); // 75
findLastIndex()的工作方式與之完全相同,只不過它提供的是元素匹配的索引,而不是元素本身。例如,列表8顯示了如何查找可被6整除的最后一個元素的索引。
列表8.使用findLastIndex()查找元素的索引
const arr = [54, 34, 55, 75, 98, 77];
arr.findLastIndex(x => x % 6 === 0); // 0
Array.prototype.toSpliced到目前為止,我們描述的所有方法也適用于。最后一個新的數(shù)組方法toSpliced()只存在于。該方法是JavaScript數(shù)組操作的復(fù)制版本——這是一種熟悉的瑞士軍刀。拼接TypedArrayArraytoSpliced () ()假設(shè)我們有一個顏色數(shù)組,我們需要在中間插入兩個新顏色(粉色和青色)??梢栽谇鍐?中看到這一點。記住,這會創(chuàng)建一個新數(shù)組,而不是修改原來的數(shù)組。
列表9.操作中的toSpliced()
const arr = ["red", "orange", "yellow", "green", "blue", "purple"]; const newArr = arr.toSpliced(2, 1, "pink", "cyan"); console.log(newArr);
// ["red", "orange", "pink", "cyan", "green", "blue", "purple"]
console.log(newArr[3]);
// 'cyan'
console.log(arr[3]);
// ‘green’
shebang是一種老式的Unix說法,表示一個標(biāo)簽后面跟著一個感嘆號(其中“bang”是“!”的俚語)。自古以來,在文件開頭的注釋就會告訴shell這里是一個可執(zhí)行腳本,以及使用什么引擎來運行它。
列表10.一個典型的bash腳本
#!/bin/bash
echo "Hello, world!"
你可以像列表10中的示例那樣直接運行一個文件,使用../hello.sh命令。在JavaScript中,你也可以做類似的操作,如列表11所示。
列表11. JavaScript中的Shebang: hello.js
#!/usr/bin/env node
console.log("Hello, world!");
列表11中的代碼告訴操作系統(tǒng)使用node程序來運行這個腳本?,F(xiàn)在,你可以直接輸入命令來運行它。如果沒有Shebang注釋,../hello.js這樣是行不通的。Shebang支持是規(guī)范中的一個功能更新,已經(jīng)在多個上下文中非官方地采用和實現(xiàn)。ECMAScript 14中的最后一個新功能是擴展了可以用作弱引用集合鍵的內(nèi)容。與日常JavaScript用法相比,弱引用集合有點晦澀。在編程中,弱引用是指如果它本來應(yīng)該被垃圾回收,那么它將被丟棄。換句話說,單獨的弱引用不足以阻止垃圾回收算法將引用目標(biāo)丟棄(這就是為什么它是弱引用)。你可以在這里了解更多關(guān)于弱引用以及它們何時有用的信息。這里也有一個很好的討論。 ES14允許在集合中使用大多數(shù)符號作為鍵,而以前只能使用對象。如果你想知道什么是符號,你并不孤單。你可以在這里了解更多關(guān)于符號的信息。這個新功能本質(zhì)上使得在集合中使用弱引用更加容易,通過放寬可以用作鍵的限制。列表12中展示了一個簡單的示例。
列表12. 在WeakMap中使用符號作為鍵
var map = new WeakMap(); // create a weak map
function useSymbol(symbol){
doSomethingWith(symbol);
var called = map.get(symbol) || 0;
called++; // called one more time
if(called > 2) console.log(“Called more than twice”);
map.set(symbol, called);
}
let mySymbol = Symbol(“FooBar”);
useSymbol(mySymbol);
useSymbol(mySymbol);
useSymbol(mySymbol);
delete mySymbol; // No live references are left to mySymbol, so we can count on the garbage collector eliminating the entry in the weakMap when it runs (eventually)
列表12是根據(jù)上面鏈接的StackOverflow答案進行修改的。在這個示例中,目的是允許從外部調(diào)用者調(diào)用計數(shù)器,并在沒有引用時銷毀映射條目。代碼本身無法知道何時不再需要引用,如果使用普通的Map,將會導(dǎo)致內(nèi)存泄漏。這是因為即使在調(diào)用它的客戶端不再需要它之后,代碼仍然會保持對引用的持有。在這種情況下,我們使用WeakMap,可以依靠垃圾回收在沒有對鍵符號的引用時刪除映射條目。
結(jié)論
盡管2023年對于JavaScript來說相對較平靜,但ECMAScript 14添加了一些有用的功能,并使官方規(guī)范與現(xiàn)實世界保持同步。在下一個版本中,我們將會看到一系列的變化,包括一個全新的Temporal API用于處理日期和時間。
作者:Matthew Tyson
更多技術(shù)干貨盡在wx“云原生數(shù)據(jù)庫”