JavaScript的規範由TC39決定。
瀏覽器廠商和相關人士定期召開會議,討論各種新功能,以決定未來的JavaScript方向。
在這裡,我們來介紹2025年已經完成的提案。
“已完成”的定義是指,現在至少有Chrome、Firefox和Safari中的兩個血統,這樣的理解基本是正確的。
也就是說,主要瀏覽器幾乎已經可以使用大部分功能實際上Chrome仍然沒有支援的功能還是不少。
在JSON.parse的引數reviver中,新增了參數context。
JSON.parse會將字串數字轉換成數字類型等,有時原始的準確值會因此遺失。
const tooBigInt = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001";
JSON.parse(tooBigInt); // 1e128
使用第二個引數reviver可以干擾轉換過程中的操作。
const reviver = (key, val) => {
console.table(val); // 1e128
return "hoge";
}
JSON.parse(tooBigInt, reviver); // "hoge"
然而,傳給reviver的第二個引數val已經是轉換過後的值,因此對於想知道原始值的需求無法有所幫助。
因此,現在可以透過第三個引數context來接收轉換前的值。
const reviver = (key, val, context) => {
console.table(context); // {source:"100000…1"}
return context.source;
}
JSON.parse(tooBigInt, reviver); // "100000…1"
這樣可以在不進行額外轉換的情況下,正確地回收原始值。
真是可喜可賀。
這是Map.getOrInsert的功能。
如果鍵存在則取得值,如果不存在則設置值,這和SQL中的UPSERT功能是一樣的。
let hoge = new Map([["foo", 1], ["bar", 2]]);
// 之前的寫法
if (!hoge.has("baz")) {
hoge.set("baz", 3);
}
// 現在的新寫法
hoge.getOrInsert("baz", 3);
hoge.getOrInsert("foo", 4); // foo仍然是1
如果鍵已經存在,則不會被覆蓋,保持原樣。
不過這個功能無法在物件上使用。
let hoge = {foo: 1, bar: 2};
hoge.has("baz"); // hoge.has is not a function
hoge.getOrInsert("baz", 3); // hoge.getOrInsert is not a function
hoge.buz ??= 3; // 3
需要與null合併賦值運算子來區分使用。
為什麼要這樣。
順便提一下,同樣的功能在Java中是computeIfAbsent,在Scala中是getOrElseUpdate,在C++中是emplace,在C#中是GetOrAdd,在Rust中是or_insert_with,在Python中是setdefault。
為什麼會這麼不一樣呢?
這是盡可能精確的加法。
let values = [1e20, 1, -1e20];
values.reduce((a, b) => a + b, 0); // 0
Math.sumPrecise(values); // 1
在計算差別很大的數時,較小的值常常會因為信息落掉而消失。
這是一個在此情況下也能進行較為精確計算的便利函數。
不過對於四捨五入的誤差似乎無法起效。
0.1 + 0.2; // 0.30000000000000004
Math.sumPrecise([0.1, 0.2]); // 0.30000000000000004
這個名字是什麼意思?
當引數的錯誤確實是一個真實錯誤時,才會返回true。
什麼叫做真實錯誤?
此提案的說明似乎過於不足,總之似乎是這樣的。
obj instanceof Error在跨域環境中判斷失敗,而偽造也是可行的。 換句話說,先前並沒有確保throw出來的Error真的是Error的方法。
因此添加了一個可以確實判定的方法。
let realError = new Error();
let fakeError = new Map();
fakeError.__proto__ = Error.prototype;
realError instanceof Error; // true
fakeError instanceof Error; // true ←
Error.isError(realError); // true
Error.isError(fakeError); // false
還有類似的方法Array.isArray()。
然而例如Map.isMap()或Iterator.isIterator()等方法並不存在,判斷一個Map是否真的是Map,或者一個Iterator是否真的是Iterator的方法並不存在。
希望能有一種通用的、類似“強”的instanceof的方法,而不是單獨添加這類方法。
合併多個迭代器。
let lows = Iterator.from([0, 1, 2, 3]);
let highs = Iterator.from([6, 7, 8, 9]);
let digits = Iterator.concat(lows, [4, 5], highs); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
這似乎只是單純地按順序合併而已。
這和下面的寫法相同
let digits = function*() {
yield* lows;
yield 4;
yield 5;
yield* highs;
}();
看起來似乎沒有類似交錯合併[0, 6, 1, 7, 2, 8, 3, 9]的功能。
將二進位數據轉換成BASE64。
// 一些二進位數據
let arr = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
// 轉換成BASE64
arr.toBase64(); // SGVsbG8gV29ybGQ=
// 轉換成HEX
arr.toHex(); // 48656c6c6f20576f726c64
// 從BASE64還原回去
Uint8Array.fromBase64("SGVsbG8gV29ybGQ=");
// 從HEX還原回去
Uint8Array.fromHex("48656c6c6f20576f726c64");
以前需要中間透過atob來進行轉換,現在似乎可以直接進行了。
這樣應該能更方便地從JS傳遞和接收二進位數據,例如圖像等吧。
從同步迭代器可以使用Array.from來創建Array,但從非同步迭代器則無法創建。
async function* asyncGen(n) {
for (let i = 0; i < n; i++)
yield i * 2;
}
const arr = await Array.from(asyncGen(4)); // []
為什麼呢?
因此現在已經可以從非同步迭代器創建Array了。
const arr = await Array.fromAsync(asyncGen(4)); // [0, 2, 4, 6]
這實質上和下面的寫法相同。
const arr = [];
for await (const v of asyncGen(4)) {
arr.push(v);
}
arr; // [0, 2, 4, 6]
正常來說,為什麼不把Array.from改成也可以接受非同步的呢?
今年又增添了許多功能。
特別是許多人在JSON解析方面可能遇到過困難吧。
反而是Error.isError,雖然知道它的意義,但實際上真的有哪裡需要這個功能而受困的現場嗎?
原文出處:https://qiita.com/rana_kualu/items/7c5305349815f5142d7d