Zenn
🎄

ENCA 24日目: IsRegExp の挙動変更(リジェクト)

2024/12/24に公開4

IsRegExp とは

ECMAScript の仕様に IsRegExp が定義されています。これは文字列のメソッド内で、渡された引数が正規表現オブジェクトかどうかを判定する際に用いられます。使われている箇所について見てみると以下の2つのパターンに分類できます。

  • 引数として文字列のみを許容するため、正規表現オブジェクトが渡ってきたら TypeError を投げたい場合
    • String.prototype.includes
    • String.prototype.startsWith
    • String.prototype.endsWith
  • 引数に正規表現オブジェクトが渡ってきたら g フラグを持っているかチェックしたい場合
    • String.prototype.matchAll
    • String.prototype.replaceAll

IsRegExp の挙動変更(リジェクト)

IsRegExp は以下のようになっています。

IsRegExp ( argument )

The abstract operation IsRegExp takes argument argument (an ECMAScript language value) and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. If argument is not an Object, return false.
  2. Let matcher be ? Get(argument, %Symbol.match%).
  3. If matcher is not undefined, return ToBoolean(matcher).
  4. If argument has a [[RegExpMatcher]] internal slot, return true.
  5. Return false.

仕様を読むと [[RegExpMatcher]] 内部スロットを持つネイティブの RegExp の他にオブジェクトが Symbol.match を実装している場合にも true を返すようになっていることがわかります。しかし正規表現の Well-known Symbols メソッドは Symbol.replace, Symbol.search, Symbol.split そして Symbol.matchAll が存在しており、Symbol.match だけ特別扱いしているのは不自然です。

というわけで2018年11月に単に [[RegExpMatcher]] 内部スロットを持つかどうかをチェックする挙動に変更しようと議論され、承認されました。しかしその後 Chromium の調査によりネイティブの RegExp ではないが Symbol.match を実装しているオブジェクトのケースが 20% ほどあることがわかり、破壊的変更になってしまうということからリジェクトされることとなってしまいました。

https://github.com/tc39/ecma262/pull/1318

https://issues.chromium.org/issues/42211715#comment12

Discussion

ぐらふぃーむぐらふぃーむ

プルリクの最後から2番目のコメント

it can be just a core-js feature detection.

が気をそそるんですけど

そもそもその feature detection は String#{includes,startsWith,endsWith} でしか使われていませんし、この変更を取り入れても旧バージョンの core-js が使われているサイトはこれらの String メソッドの古い挙動が core-js の polyfill によって保たれるんですから互換性がそもそもあるのでは?

まあ依然として V8RegExpMatchIsTrueishOnNonJSRegExp の 0.03% を調査しないといけないんですけど

petamorikenpetamoriken

core-js を使っている場合は問題ないという認識です。ただ npm パッケージで機能追加された正規表現ライブラリが提供されることがあるので、きっとその中にネイティブの RegExp を継承していないものがあるんでしょうね……。

ぐらふぃーむぐらふぃーむ

core-js を抜いたら V8RegExpMatchIsFalseishOnJSRegExp が何%になるか気になりますけど、調べる方法ありますかね……

petamorikenpetamoriken

正確に調べる方法が思いつかないですね……。通常の提案を入れる時のように Chrome Canary に入れてみて壊れるサイトがないか確かめるしかない気がします。

ログインするとコメントできます