ECMAScript仕様輪読会 #102
前回: ECMAScript仕様輪読会 #101
Cosenseの招待リンク: https://scrapbox.io/projects/esspec/invitations/85b96c9fa718ce5185e307196ed8fb53
connpass: https://esspec.connpass.com/
ES Spec Draft: https://tc39.es/ecma262/
multipage: https://tc39.es/ecma262/multipage/
X hashtag: #esspec
便利ツール
esspec-memo: https://tars0x9752.github.io/esspec-memo/esspec.html
Scrapbox Codeblock Generator: https://vzvu3k6k.github.io/scrapbox-codeblock/
TC39 Terminology: https://github.com/tc39/how-we-work/blob/main/terminology.md
esmeta playground: https://es-meta.github.io/playground/
時事ネタ
フロカン東京
https://note.com/fec_tokyo/n/nfa9aa6606721
フロカン福岡
https://frontend-conf.fukuoka.jp/2026/news/2026-05-11-general_call-for-proposal?hl=ja
自己紹介 (近況報告)
syumai syumai.icon
X: https://x.com/__syumai GitHub: https://github.com/syumai
TSを書いて暮らしてます
TSKaigiで話してきました
https://speakerdeck.com/syumai/how-oxlint-calls-tsgolint
iwatsurut
とくに、イベントもなく過ごしています。
igrep(山本悠滋)
https://github.com/igrep/
関数型まつりの発表の日程が決まった。2026/07/12 15:30〜
https://fortee.jp/2026fp-matsuri/proposal/477e0574-83a4-490b-9d89-ada5178c72c6
maru。(まる)
https://x.com/sbleru
https://github.com/sbleru
主にTSで仕事してます。React, Node。
年内で家がなくなることになったのでどうしようか考え中
気になっているやつ
https://gihyo.jp/book/2026/978-4-297-15565-0
同時編集JavaScript Playground
前半
https://jssync.syumai.workers.dev/rooms/esspec_a
後半
https://jssync.syumai.workers.dev/rooms/esspec_b
前回のあらすじ
https://syumai.github.io/esspec/summaries/summary-101.html
今回のメモ
matchAll
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll
英語
5. Let truncatedStringFiller be the String value consisting of repeated concatenations of fillString truncated to length fillLen.
5. truncatedStringFiller を、fillString を繰り返して連結し、その長さを fillLen に切り詰めた文字列の値とする。
自然だ、、
code:js
// ===== Code =====
// https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.matchall
{
console.log(..."abcdeabcde".matchAll(/.c./g));
// g flagがついていないのでエラー
try {
console.log(..."abcdeabcde".matchAll(/.c./));
} catch(err) {
console.error(err);
}
}
// %Symbol.match% プロパティがあるパターン
{
const myRegExp = {
Symbol.match: function (){
return 1;
},
Symbol.matchAll: function (){
return 2;
},
flags: "g" // これが必要
}
console.log("abcdeabcde".matchAll(myRegExp));
}
// %Symbol.match% プロパティがないパターン
{
const myRegExp = {
Symbol.matchAll: function (){
return 2;
},
}
console.log("abcdeabcde".matchAll(myRegExp));
}
// 引数が文字列のパターン
{
console.log(..."aaaaaaa".matchAll("a."));
}
{
console.log(..."nullish".matchAll(null));
}
// ===== Output =====
bcd bcd
TypeError: String.prototype.matchAll called with a non-global RegExp argument
2
2
aa,aa,aa
null
code:js
// ===== Code =====
// https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.padend
// padEnd
{
console.log("abc".padEnd(8));
console.log("abc".padEnd(8, "xy"));
}
// padStart
{
console.log("abc".padStart(8));
console.log("abc".padStart(8, "xy"));
}
// padEndの例外パターン
{
console.log(String.prototype.padStart.call(null, 5));
}
// ===== Output =====
abc
abcxyxyx
abc
xyxyxabc
TypeError: String.prototype.padStart called on null or undefined
懐かしのleft-pad事件
https://postd.cc/npm-and-left-pad/
https://github.com/tc39/proposal-string-pad-start-end
code:js
// ===== Code =====
// https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.repeat
{
console.log("abc".repeat(3));
console.log("0".repeat(2.5));
console.log("0".repeat(3.5));
console.log("0".repeat(-.5));
}
// intentionally generic
{
console.log(String.prototype.repeat.call({}, 3));
}
// 例外パターン
{
try {
console.log(String.prototype.repeat.call(null, 3));
} catch (err) {
console.error(err)
}
try {
console.log("0".repeat(-1));
} catch (err) {
console.error(err)
}
}
// ===== Output =====
abcabcabc
00
000
object Objectobject Objectobject Object
TypeError: String.prototype.repeat called on null or undefined
RangeError: Invalid count value: -1
code:js
// ===== Code =====
// https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.replace
{
// MDN https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace
const paragraph = "I think Ruth's dog is cuter than your dog!";
console.log(paragraph.replace("Ruth's", "my"));
// 予想される結果: "I think my dog is cuter than your dog!"
const regex = /Dog/i;
console.log(paragraph.replace(regex, "ferret"));
// 予想される結果: "I think Ruth's ferret is cuter than your dog!"
// replace / replaceAllの違い
console.log(paragraph.replace("dog", "ferret"));
console.log(paragraph.replaceAll("dog", "ferret"));
// もともとこれでreplaceAllできてはいた
console.log(paragraph.replace(/dog/g, "ferret"));
}
// ===== Output =====
I think my dog is cuter than your dog!
I think Ruth's ferret is cuter than your dog!
I think Ruth's ferret is cuter than your dog!
I think Ruth's ferret is cuter than your ferret!
I think Ruth's ferret is cuter than your ferret!
code:js
// ===== Code =====
// https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.replace
// Symbol.replace自前実装パターン
{
const myRegExp = {
Symbol.replace(thisValue, replaceValue){
return thisValue + replaceValue;
},
}
console.log("I think Ruth's dog is cuter than your dog!".replace(myRegExp, "ferret"));
}
// ===== Output =====
I think Ruth's dog is cuter than your dog!ferret
code:js
// ===== Code =====
// https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.replace
// Functional replaceパターン
{
// MDN https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace
const paragraph = "I think Ruth's dog is cuter than your dog!";
// String.prototype.replaceによるfunctional replacement
console.log(paragraph.replace("dog", (m) => m.toUpperCase()));
console.log(paragraph.replace("dog", (searchValue, position, thisValue) => (
console.log(JSON.stringify({ searchValue, position, thisValue }, null, 2)),
searchValue.toUpperCase()
)));
// RegExp.prototype%Symbol.replace%によるfunctional replacement
console.log(paragraph.replace(/dog/g, (m) => m.toUpperCase()));
console.log(paragraph.replace(/dog/g, (searchValue, position, thisValue) => (
console.log(JSON.stringify({ searchValue, position, thisValue }, null, 2)),
searchValue.toUpperCase()
)));
}
// ===== Output =====
I think Ruth's DOG is cuter than your dog!
{
"searchValue": "dog",
"position": 15,
"thisValue": "I think Ruth's dog is cuter than your dog!"
}
I think Ruth's DOG is cuter than your dog!
I think Ruth's DOG is cuter than your DOG!
{
"searchValue": "dog",
"position": 15,
"thisValue": "I think Ruth's dog is cuter than your dog!"
}
{
"searchValue": "dog",
"position": 38,
"thisValue": "I think Ruth's dog is cuter than your dog!"
}
I think Ruth's DOG is cuter than your DOG!