Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
イテレータとイテラブルの概要と課題、未来
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
sosukesuzuki
November 23, 2024
4k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
イテレータとイテラブルの概要と課題、未来
JSConf JP 2024
sosukesuzuki
November 23, 2024
More Decks by sosukesuzuki
See All by sosukesuzuki
JavaScriptにおけるasync/await呼び出しのスタックトレースの困難と実装
sosukesuzuki
12
9.2k
一人で大規模OSSに立ち向かうには
sosukesuzuki
21
14k
デザインシステムと生成AIの相性について考える
sosukesuzuki
4
1.6k
JavaScriptCoreのObject.groupBy/Map.groupByのバグを自分で報告して自分で直す
sosukesuzuki
1
730
「書いたJavaScriptがそのままブラウザで動く未来へ」スピーカーノート
sosukesuzuki
8
12k
Prettier 3.0 の VSCode 拡張対応における技術的な意思決定~VSCode 拡張で dynamic import が動かない~
sosukesuzuki
1
2.2k
ESM移行は無理だけどおれもSindreのライブラリが使いたい!
sosukesuzuki
2
1.3k
JavaScript エコシステムを維持する OSS の努力と課題
sosukesuzuki
14
10k
Prettierに従わなくてもいい場合
sosukesuzuki
7
3.3k
Featured
See All Featured
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Color Theory Basics | Prateek | Gurzu
gurzu
0
360
For a Future-Friendly Web
brad_frost
183
10k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Git: the NoSQL Database
bkeepers
PRO
432
67k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
55k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.3k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Designing Experiences People Love
moore
143
24k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
2
1.1k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.2k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
580
Transcript
イテレータとイテラブルの概要と課題、未 来 JSConf 2024
#jsconfjp_b
自己紹介 SUZUKI Sosuke ( @__sosukesuzuki ) • ユビー株式会社 プロダクト開発エンジニア •
筑波大学 情報学群 情報科学類 B4 • WebKit コミッター • Prettier メンテナー
この話のモチベーション 日常的にJavaScriptやTypeScriptを書いている人であっても、 イテレータ・イテラブルについてちゃんと理解して、活用して いる人は少ない。 イテレータ・イテラブルは強力な言語機能だから、使うべきと きに使えないのはもったいない。 だから、知ってほしい。
この話のモチベーション この発表の目的は、聞いた皆さんが、 1. 日常のプログラミングの中でイテレータやイテラブルを使う ことを考えられるようになること 2. ライブラリ・フレームワークがイテレータ・ジェネレータを 前提にしたインタフェースを持っていても臆することなく使 いこなせるようになること
話すこと 1. イテレータ・イテラブルの基本 2. イテレータ・イテラブルのユースケース 3. イテレータ・イテラブルはなぜあまり使われないのか 4. 最新、そしてちょっと未来のイテレータ・イテラブル 5.
まとめ
1. イテレータとイテラブルの基本
イテレータ・イテラブルの基本 イテレータ・イテラブルを一言でいうと 「連続して生成される値を一貫したインタフェースで取り扱 うための仕組み」
イテレータ・イテラブルの基本 連続した値を反復して処理したくなることがある。JavaScript でよく使われる反復の対象はArray。
イテレータ・イテラブルの基本 for (const foo of bar) {} の of の右側にArrayを書くことが多
い。しかし、実際には イテラブル であればどんなオブジェク トでも書くことができる。 Array、Set、Mapなどの組み込みコレクションはイテラブルで あるため、for of 構文で反復して処理できる。
イテレータ・イテラブルの基本 イテラブルとはIterable Interface を満たすオブジェクト のこ と。 イテラブルは、Symbol.iteratorという名前のプロパティを 持っていて、そのプロパティはイテレータを返す関数。
イテレータ・イテラブルの基本 余談 • JavaScriptでは { [symbol]: value } という記法でシンボ ルの値をキーに持つオブジェクトを作れる
• Symbol.iteratorのようにSymbol.hogeという形をしている のは Well-known Symbolsと呼ばれている。JavaScriptの 様々な隠れ挙動を制御するために使われる特別なシンボル
イテレータ・イテラブルの基本 ArrayやSetはイテラブル、つまりSymbol.iterator関数があ る。この関数を直接呼び出すこともできる。 ArrayのSymbol.iterator関数はArray Iteratorというイテレー タを返す。
イテレータ・イテラブルの基本 イテラブルでなければ for…of の of の右側に置くことはでき ない。意図的にIterableInterfaceを満たさなくなるように Arrayオブジェクトを破壊してみると、エラーになる。
イテレータ・イテラブルの基本 説明したこと • イテラブルであれば for…of で反復処理できること ◦ 組み込みコレクションのArrayやSetもイテラブルの一種 であること •
イテラブルは、Symbol.iterator プロパティがイテレータを 返す関数であるようなオブジェクトであること
イテレータ・イテラブルの基本 イテレータは、Iterator Interfaceを満たすオブジェクトのこ と。Iterator Interface では、一つの必須プロパティ(next関 数)と二つのオプショナルなプロパティ(return と throw)が決 められている。
イテレータ・イテラブルの基本 ※ この発表では return と throw については触れません。すで に色々な人が日本語で記事を書いてくれているので、そちらを 参照してください: •
Masaki Hara. 2021. JavaScriptのIterator / Generatorの整理. https://zenn.dev/qnighy/articles/112af47edfda96 • uhyo. 2024. イテレータを分岐させるとどうなる? Iterator Helpersに見 るJavaScriptのイテレータの挙動. https://zenn.dev/uhyo/articles/iterator-helpers-iterator-close
イテレータ・イテラブルの基本 next、return、throwはIteratorResult Interfaceを返す関 数。IteratorResult Interface は boolean の done プロパティ
と、何かしらの値を持つ value プロパティを持っている。
イテレータ・イテラブルの基本 シンプルなオリジナルのイテレータ・イテラブル。
イテレータ・イテラブルの基本 変数iterableはイテラブルなので、for…ofで反復できる。やっ てみると... 1が無限に出力されている。変数iteratorのnext関数が返してい る value: 1 が element に入ってそうな、感じがする。
イテレータのnextメソッドをちょっといじってみる。
イテレータ・イテラブルの基本 iterator は counter というプロパティを持つ。next 関数で counter をインクリメントし、5 以上であれば done
が true の IteratorResult を返す。
イテレータ・イテラブルの基本 iteratorだけ更新して、もう一度同じコードを実行してみると 書いたとおりに4で止まっている!
イテレータ・イテラブルの基本 この動作から、 1. 反復のたびにiteratorのnextメソッドが呼び出されているこ と 2. doneがtrueのIteratorResultを返すと反復が止まること がわかる。 これがイテレータ・イテラブルの正体。ArrayやSetなどの標準 コレクションもこうなっている。
イテレータ・イテラブルの基本 Arrayはイテラブルだがイ テレータではない。Array の裏にはArrayIteratorと いうイテレータが隠れてい る。このイテレータのnext 関数を直接使ってみる。 ArrayIteratorのnextは ベースのArrayの要素を一 つずつ返すことがわかる。
イテレータ・イテラブルの基本 ジェネレータのことも思い出してみよう。みなさん覚えてます か。redux-sagaでよく書きましたよね。
イテレータ・イテラブルの基本 この function* で始まる関数を ジェネレータ関数 という。 ジェネレータ関数は ジェネレータ を返す。
イテレータ・イテラブルの基本 ジェネレータはイテレータか つイテラブル。なので、next 関数を持っている。ジェネ レータのnext関数は、ジェネ レータ関数の中でyieldされた 値を生成する。
イテレータ・イテラブルの基本 ジェネレータ関数は、yieldで処理を中断し、nextの呼び出し で処理を再開できる関数。 「Promiseはあるがasync/awaitはない」という時代には、 ジェネレータでasync/await風の書き味を実現するライブラリ もあった( https://github.com/tj/co など)。ジェネレータ関数 内でPromiseがyieldされたらresolveもしくはrejectされるま で待ち、resolveされたらnextで再開する。
イテレータ・イテラブルの基本 これまでの話を整理すると • for…ofのofの右側にはイテラブルを書ける • ArrayやSetなどはイテラブルである • イテラブルは、Symbol.iterator関数を持つオブジェクトで ある。その関数はイテレータを返す。 •
イテレータはnext関数を持つオブジェクトである。その関 数は { done: boolean, value: any } の形のオブジェクトを 返す。 • ジェネレータはイテレータかつイテラブルである
イテレータ・イテラブルの基本 ちなみに、非同期イテレータ・非同期イテラブルもある。 イテレータのnext関数がIteratorResultオブジェクトを返すの に対して、非同期イテレータのnext関数は Promise<IteratorResult> を返す。 イテラブルの Symbol.iterator 関数がイテレータを返すのに対 して、非同期イテラブルの
Symbol.asyncIterator 関数は非 同期イテレータを返す。
イテレータ・イテラブルの基本
イテレータ・イテラブルの基本 • next関数がPromise を返している • 非同期イテラブルは Symbol.asyncIterat or関数を持つ • for
await of という 構文で反復している
イテレータ・イテラブルの基本 これらを踏まえた上で、冒頭の主張について考えてみる。
イテレータ・イテラブルの基本 イテレータ・イテラブルを一言でいうと 「連続して生成される値を一貫したインタフェースで取り扱 うための仕組み」
イテレータ・イテラブルの基本 イテレータ・イテラブルを一言でいうと 「連続して生成される値を一貫したインタフェースで取り扱 うための仕組み」 イテレータのnext関数に よって生成される
イテレータ・イテラブルの基本 イテレータ・イテラブルを一言でいうと 「連続して生成される値を一貫したインタフェースで取り扱 うための仕組み」 for (const foo of bar) {}
など
イテレータ・イテラブルの基本 ちなみに、イテラブルは他にも色んなところで使える • for…of • Array.from • スプレッド構文 • 分割代入
• MapやSetのコンストラクタ • Promise.all など • yield* など
2. イテレータとイテラブルのユースケース
2. イテレータとイテラブル 組み込みではないカスタムの やジェネレータのユースケース
イテレータ・イテラブルのユースケース たとえば、こういうユースケースがある: 1. カスタムのリスト風データ構造に対して反復処理がしたい 2. 無限のリストがほしい 3. メモリに載せたくないくらいデカイデータセットに対して 反復処理がしたい 4.
非同期で生成されるデータストリームに対して反復処理が したい
イテレータ・イテラブルのユースケース こういう連結リストがあると する。こいつはこのままだと for…ofでループしたり、分割 代入したりできない。 1. カスタムのリスト風データ構造に対して反復 処理がしたい
イテレータ・イテラブルのユースケース こういうSymbol.iteratorがあれば、 for…of でループできて嬉しい。 1. カスタムのリスト風データ構造に対して反復 処理がしたい
イテレータ・イテラブルのユースケース 大人気のコレクションであるArrayやSetは、すべての要素がメ モリに乗るため、無限だったりめちゃくちゃデカかったりする リストを表現するのが難しい。 2. 無限のリストがほしい
イテレータ・イテラブルのユースケース ジェネレータを使うと簡単 に実現できて嬉しい。 generatorのnext関数を呼 ぶと値が1ずつ増えていき、 何度でも呼び出せる。 2. 無限のリストがほしい
イテレータ・イテラブルのユースケース メモリに載せたくないくらいめちゃくちゃデカイデータセット があって、それを反復処理したいような状況。 HDD上にあるめっちゃデカイCSVファイルを処理したい、と か。 3. メモリに載せたくないくらいデカイデータ セットに対して反復処理がしたい
イテレータ・イテラブルのユースケース 有名なCSVパーサーライブラリ であるnode-csvでは、パース 結果を非同期イテラブルとして 扱える。 3. メモリに載せたくないくらいデカイデータ セットに対して反復処理がしたい
イテレータ・イテラブルのユースケース 非同期で生成されるデータのストリームを非同期イテラブルと して表現できれば、for await of を使って反復処理できる。 たとえば、Bunのconsoleオブジェクトは非同期イテラブルに なっている(びっくり!)。 4. 非同期で生成されるデータストリームに対し
て反復処理がしたい
イテレータ・イテラブルのユースケース consoleのイテレータのnext関 数は、入力された行を非同期で 取得して返す。 Console Standardsにはない挙 動なので否定的な意見もある が、非同期イテラブルの使い方 としては面白い。 4.
非同期で生成されるデータストリームに対し て反復処理がしたい
イテレータ・イテラブルのユースケース こういうユースケースに遭遇したら、イテレータチャンス! 1. カスタムのリスト風データ構造に対して反復処理がしたい 2. 無限のリストがほしい 3. メモリに載せたくないくらいデカイデータセットに対して 反復処理がしたい 4.
非同期で生成されるデータストリームに対して反復処理が したい
3. イテレータとイテラブルはなぜあまり使 われないのか
イテレータ・イテラブルはなぜあまり使わ れないのか 実は、イテレータ・イテラブルを使うべき状況に遭遇すること はあんまりない、という根本的な理由がある。 ArrayやSetを使うべきときに無理にカスタムイテレータや ジェネレータを使うのは悪手。性能は落ちるし使いにくいは ず。
イテレータ・イテラブルはなぜあまり使わ れないのか しかし、とはいえ、我々JavaScriptプログラマーはイテレータ ・イテラブルについて無知すぎる、と思う。 ジェネレータのyield, yield*の意味論を知らない。イテレータ ・イテラブル、非同期イテレータ・非同期イテラブルの構造、 作り方を知らない。 コードを書くときに、それらを使うという発想に至らない。
イテレータ・イテラブルはなぜあまり使わ れないのか そして、これまでのイテレータはぶっちゃけあんまり便利では なかった。イテレータが便利な言語には、いろんな便利関数が あったりする(たとえばRust)。 JavaScript(ECMAScript 2024時点)では、ほとんどない。 カスタムイテレータを作ったり、ジェネレータを使ったりして も、それを便利に使うことができない。
4. 最新、そしてちょっと未来の イテレータ・イテラブル
最新、そしてちょっと未来の イテレータ・イテラブル Iterator HelpersというStage 4のECMAScript プロポーザル がある。 2024年10月のTC39(東京開催)で、Stage 4になり、主要な3 つのJavaScript処理系(V8、SpiderMonkey、JavaScriptCore)
ではすでに実装されている。
最新、そしてちょっと未来の イテレータ・イテラブル Iterator Helpersの前に、いくつか の前提。 Arrayオブジェクトのイテレータで あるArrayIteratorオブジェクト は、%ArrayIteratorPrototype% を継承する %ArrayIteratorPrototype%
は%IteratorPrototype%を継承す %ArrayIteratorPrototype% ArrayIterator オブジェクト (イテレータ) Arrayオブジェクト (イテラブル) %IteratorPrototype% Symbol.iterator 継承 継承
最新、そしてちょっと未来の イテレータ・イテラブル %IteratorPrototype%は直接アク セスできない、いわば隠れオブジェ クトだった (Object.getPrototypeOfなどを使 うとアクセスできる) %ArrayIteratorPrototype% ArrayIterator オブジェクト
(イテレータ) Arrayオブジェクト (イテラブル) %IteratorPrototype% Symbol.iterator 継承 継承
最新、そしてちょっと未来の イテレータ・イテラブル 思い出そう %ArrayIteratorPrototype% ArrayIterator オブジェクト (イテレータ) Arrayオブジェクト (イテラブル) %IteratorPrototype%
Symbol.iterator 継承 継承
最新、そしてちょっと未来の イテレータ・イテラブル Arrayに限らず、SetやMapなどの組み込みイテラブルのイテ レータは、間接的に %IteratorPrototype% を継承している
最新、そしてちょっと未来の イテレータ・イテラブル Iterator Helpersプロポーザルは、以下の3つの重要な変更を 加えた: 1. %IteratorPrototype% とそのコンストラクタをグローバ ルに公開した 2.
%IteratorPrototype% に便利なヘルパー関数を追加した 3. 普通のオブジェクトにあとから %IteratorPrototype% を 継承させる方法を提供した
最新、そしてちょっと未来の イテレータ・イテラブル Iterator Helpersプロポーザルは • Iterator コンストラクタ • Iterator.prototype (=
%IteratorPrototype% ) をグローバルに公開した。
最新、そしてちょっと未来の イテレータ・イテラブル Iterator Helpersプロポーザルは以下のヘルパー関数を %IteratorPrototype% に追加した • map • filter
• take • drop • flatMap • reduce • toArray • forEach • some • every • find
最新、そしてちょっと未来の イテレータ・イテラブル Iterator Helpersプロポーザルは、普通のオブジェクトにあと から %IteratorPrototype% を継承させる方法を提供した。
最新、そしてちょっと未来の イテレータ・イテラブル Iteratorを継承したクラスを作ることもできる。 直接 new はできない。
最新、そしてちょっと未来の イテレータ・イテラブル Iterator Helpersがあると、こういうコードが書ける。
最新、そしてちょっと未来の イテレータ・イテラブル Iterator Helpersは素晴らしいが、これだけではちょっと... • map • filter • take
• drop • flatMap • reduce • toArray • forEach • some • every • find
最新、そしてちょっと未来の イテレータ・イテラブル ということで、いくつかのプロポーザルがある • Iterator.zip (Stage 2.7) https://github.com/tc39/proposal-joint-iteration • Iterator.concat
(Stage 2.7) https://github.com/tc39/proposal-iterator-sequencing • Async Iterator Helpers (Stage 2) https://github.com/tc39/proposal-async-iterator-helpers • Iterator.range (Stage 2) https://github.com/tc39/proposal-iterator.range • Iterator chunking (Stage 2) https://github.com/tc39/proposal-iterator.range
5. まとめ
まとめ イテラブルは イテレータは
まとめ • for…ofをはじめとしたいろんな構文、ビルトイン関数はイ テラブルを受け取る。 • 以下の場合に、イテレータ・ジェネレータとして表現する ことを検討しよう ◦ カスタムのリスト構造を扱うとき ◦
無限のリストを扱うとき ◦ メモリに載せたくないくらいデカイデータを扱うとき ◦ 非同期に生成されるデータストリームを扱うとき
まとめ • 最近のJavaScriptには、Iterator.prototype にいろんなヘ ルパーが追加されている。 ◦ 自分のオリジナルイテレータに Iterator.prototype を 継承させれば(Iterator.from
や Iterator コンストラク タによって)ヘルパーを使える。 • 他にも新たなヘルパーを追加するプロポーザルがアクティ ブに動いている。