ES2021 追加予定の機能が増えてた
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ Promise.any
◆ WeakRef
◆ &&=, ||=, ??=
◆ 1_000_000
◆ WeakRef
◆ &&=, ||=, ??=
◆ 1_000_000
しばらく見てなかったので JavaScript の新機能のステータスを見てみました
https://github.com/tc39/proposals/blob/master/finished-proposals.md
以前見たときには ES2021 予定は replaceAll だけだったのに
が増えています
どれもブラウザで動かせたので使ってみました
今 84 なので次のリリース (今月末) です
beta 版なら今でも使えます
これまで文字列を置換しようとすると replace メソッドを使っていました
検索対象は文字列型と正規表現型の両方を受け取れましたが 文字列型の場合は最初の 1 つしか置換してくれません
全部を置換したい場合は正規表現型にして g オプションが必須です
検索文字が固定で リテラルで書くのならともかく ユーザー入力値だと正規表現型に変換するのはひと手間必要ですし 正規表現で特殊な意味を持つ使う文字列が含まれることもあるため エスケープが必要です
それなのに JavaScript の標準機能では正規表現用のエスケープをする関数が用意されていません
その不便さを解消してくれるのが replaceAll です
文字列型の指定で見つかった全部を置換してくれます
初期の Promise のメソッドは resolve/reject を除くと all と race がありました
これらは複数の Promise を組み合わせて 1 つの Promise にしてくれるものです
この系統で ES2020 で allSettled が追加され ES2021 では any が追加になります
any は all と対応するもので all がすべての Promise が成功したら成功になるのに対し any はどれかの Promise が成功したら成功になります
全部失敗にならなければ途中で失敗があっても無視されます
race というのもありますが こっちだと成功失敗とわずに一番最初に状態が変わった Promise の結果になります
10 個中 9 個が失敗しても 最後の 1 つが成功なら成功としてその結果がほしいというときには使えません
そういうときに使うために新しくできたものが any です
まとめると
すでに WeakMap や WeakSet がありそれに近い Weak 系ですがこれらとはちょっと違うものです
WeakRef のコンストラクタに弱参照化したいオブジェクトを渡します
WeakMap などのようにオブジェクトである必要があって 1 とか入れるとエラーになります
弱参照化したオブジェクトは WeakRef インスタンスの deref メソッドを呼び出すと取得できます
ただし 弱参照化されたオブジェクトは この WeakRef 外に参照がなければ GC の対象になります
GC されると deref で取得できなくなり undefined が返ってきます
消えるのは GC のタイミング次第なので devtools を使ってると消えなかったりで確認がしづらいものです
こういうページを用意しました
devtools がなくても確認できるように画面に追記します
obj.value が弱参照化するもので 一度 deref 結果を表示したら null で上書きし GC 対象にします
その後すぐと毎秒ごとに deref 結果を追記します
結果はこうなりました
8 秒後までは残っていて 9 秒後には GC されていました
これは Chrome 84 での結果ですが GC 次第なので ページの重さとかブラウザの種類とかでタイミングは変わります
これのおかげでどこかに参照が残っていてメモリリークになってないかのチェックがやりやすくなりますね
これまででも WeakSet に入れておいて devtools で見るとか工夫すれば一応できましたけどあんまりやりやすいものでもなく 裏技っぽい方法でしたし
JavaScript の二項演算子 +, *, & などには +=, *=, &= と言った = 付きのものがあります
しかし && と || にはなぜかありませんでした
<< や >> や ** にはあるので 2 文字だからパーサの問題でというわけでもないと思います
入れない理由もないからか && と || にも = 付きの &&= と ||= が追加され使えるようになりました
最近追加された ?? 演算子も || と同じような扱いだったので = 付きがありませんでしたが ??= も追加されました
数値のリテラルに _ を挟んで読みやすくかけます
完全に自由に _ を入れられるわけでもなく _ を 2 連続で書けなかったり最初と最後に書けないなどの制限はあります
長くなると適度な区切りで __ を使ったりしたいんですけどね
他言語だと Rust は連続ありですが Python はダメでした
この辺は言語次第ですね
https://github.com/tc39/proposals/blob/master/finished-proposals.md
以前見たときには ES2021 予定は replaceAll だけだったのに
- Promise.any
- WeakRefs
- Logical Assignment Operators
- Numeric separators
が増えています
どれもブラウザで動かせたので使ってみました
String.prototype.replaceAll
これは Chrome 85 から使えます今 84 なので次のリリース (今月末) です
beta 版なら今でも使えます
これまで文字列を置換しようとすると replace メソッドを使っていました
検索対象は文字列型と正規表現型の両方を受け取れましたが 文字列型の場合は最初の 1 つしか置換してくれません
全部を置換したい場合は正規表現型にして g オプションが必須です
"foo".replace("o", "a")
// "fao"
"foo".replace(/o/, "a")
// "fao"
"foo".replace(/o/g, "a")
// "faa"
検索文字が固定で リテラルで書くのならともかく ユーザー入力値だと正規表現型に変換するのはひと手間必要ですし 正規表現で特殊な意味を持つ使う文字列が含まれることもあるため エスケープが必要です
それなのに JavaScript の標準機能では正規表現用のエスケープをする関数が用意されていません
その不便さを解消してくれるのが replaceAll です
文字列型の指定で見つかった全部を置換してくれます
"foo".replaceAll("o", "a")
// "faa"
Promise.any
これも Chrome 85 からです初期の Promise のメソッドは resolve/reject を除くと all と race がありました
これらは複数の Promise を組み合わせて 1 つの Promise にしてくれるものです
この系統で ES2020 で allSettled が追加され ES2021 では any が追加になります
any は all と対応するもので all がすべての Promise が成功したら成功になるのに対し any はどれかの Promise が成功したら成功になります
全部失敗にならなければ途中で失敗があっても無視されます
race というのもありますが こっちだと成功失敗とわずに一番最初に状態が変わった Promise の結果になります
10 個中 9 個が失敗しても 最後の 1 つが成功なら成功としてその結果がほしいというときには使えません
そういうときに使うために新しくできたものが any です
まとめると
all:
resolved:
全部が resolved になったとき
rejected:
どれかが rejected になったとき
any:
resolved:
どれかが resolved になったとき
rejected:
全部が rejected になったとき
race:
resolved:
どれかが resolved になったとき
rejected:
どれかが rejected になったとき
allSettled:
resolved:
全部が resolved か rejected になったとき
rejected:
ならない
WeakRefs
これは Chrome 84 で使えますすでに WeakMap や WeakSet がありそれに近い Weak 系ですがこれらとはちょっと違うものです
WeakRef のコンストラクタに弱参照化したいオブジェクトを渡します
WeakMap などのようにオブジェクトである必要があって 1 とか入れるとエラーになります
弱参照化したオブジェクトは WeakRef インスタンスの deref メソッドを呼び出すと取得できます
ただし 弱参照化されたオブジェクトは この WeakRef 外に参照がなければ GC の対象になります
GC されると deref で取得できなくなり undefined が返ってきます
消えるのは GC のタイミング次第なので devtools を使ってると消えなかったりで確認がしづらいものです
こういうページを用意しました
<!doctype html>
<div id="t"></div>
<script>
const log = (...args) => {
t.innerText += args.map(a => JSON.stringify(a)).join(" ") + "\n"
}
const obj = {
value: { a: 1 }
}
const ref = new WeakRef(obj.value)
log(ref.deref())
obj.value = null
log(ref.deref())
let n = 0
setInterval(() => {
log(++n, ref.deref())
}, 1000)
</script>
devtools がなくても確認できるように画面に追記します
obj.value が弱参照化するもので 一度 deref 結果を表示したら null で上書きし GC 対象にします
その後すぐと毎秒ごとに deref 結果を追記します
結果はこうなりました
{"a":1}
{"a":1}
1 {"a":1}
2 {"a":1}
3 {"a":1}
4 {"a":1}
5 {"a":1}
6 {"a":1}
7 {"a":1}
8 {"a":1}
9
10
11
12
8 秒後までは残っていて 9 秒後には GC されていました
これは Chrome 84 での結果ですが GC 次第なので ページの重さとかブラウザの種類とかでタイミングは変わります
これのおかげでどこかに参照が残っていてメモリリークになってないかのチェックがやりやすくなりますね
これまででも WeakSet に入れておいて devtools で見るとか工夫すれば一応できましたけどあんまりやりやすいものでもなく 裏技っぽい方法でしたし
Logical Assignment Operators
これは Chrome 85 からですJavaScript の二項演算子 +, *, & などには +=, *=, &= と言った = 付きのものがあります
しかし && と || にはなぜかありませんでした
<< や >> や ** にはあるので 2 文字だからパーサの問題でというわけでもないと思います
入れない理由もないからか && と || にも = 付きの &&= と ||= が追加され使えるようになりました
最近追加された ?? 演算子も || と同じような扱いだったので = 付きがありませんでしたが ??= も追加されました
let a = true
a &&= false
// false
a
// false
a ||= true
// true
a
// true
a = null
a ??= 1
// 1
a
// 1
a ??= 2
// 1
a
// 1
Numeric separators
これは以前から使えたものです数値のリテラルに _ を挟んで読みやすくかけます
123 === 1_2_3
// true
1_000_000_000.000_001
// 1000000000.000001
完全に自由に _ を入れられるわけでもなく _ を 2 連続で書けなかったり最初と最後に書けないなどの制限はあります
長くなると適度な区切りで __ を使ったりしたいんですけどね
他言語だと Rust は連続ありですが Python はダメでした
この辺は言語次第ですね