Slide 1

Slide 1 text

あなたの知らない の世界 id:mizdra 2024/11/23 JSConf JP 2024 1 Function.prototype.toString()

Slide 2

Slide 2 text

自己紹介 ● mizdra (みずどら) ● インターネット大好き ● 株式会社はてな ○ フロントエンドエキスパート ○ 社内のフロントエンド啓発活動 2

Slide 3

Slide 3 text

3 今日のテーマ

Slide 4

Slide 4 text

4 Function.prototype. toString()

Slide 5

Slide 5 text

5 Function.prototype. toString() Function.prototype.toString() ● 多分あんまり知られてない ● 今日は全員にこの API のことを知って帰ってもらえれば

Slide 6

Slide 6 text

6 Function.prototype. toString() どんな API? ● 関数のソースコードを取り出せる API ● 関数 (例: add) に対して add.toString() を呼び出す ○ add 関数のソースコードが得られる

Slide 7

Slide 7 text

7 例: add 関数を toString()

Slide 8

Slide 8 text

8 Function.prototype. toString() そんだけ? って感じだけど ● 実は色々な用途がある ● 著名ライブラリの中でも使われてる ● 今日の内容 ○ 実用的な使い方から ○ 変わった使い方まで ○ 色々紹介

Slide 9

Slide 9 text

9 用途① 関数の転送

Slide 10

Slide 10 text

10 Function.prototype. toString() 「関数の転送...?」 ● 関数って送信できないのでは...? ● 普通送信するには... ○ serializable じゃないといけない ● 関数は serializable じゃない

Slide 11

Slide 11 text

11 Function.prototype.toString() 使えばできる

Slide 12

Slide 12 text

12 Function.prototype. toString() 関数の転送の仕方 1. 送信側: fn.toString() 2. 送信側: 得られた文字列を送信 3. 受信側: const fn = eval(fnStr) 4. 受信側: fn()

Slide 13

Slide 13 text

13 Puppeteer でやってる

Slide 14

Slide 14 text

14 Puppeteer ● Node.js 向けのヘッドレスブラウザ操作ライブラリ ● Page#evaluate(fn, arg) ○ 関数を引数に渡せる ○ ブラウザのWebページ上で、関数を実行

Slide 15

Slide 15 text

15 例: ヘッダーのテキストを取得する

Slide 16

Slide 16 text

16 例: ヘッダーのテキストを取得する Node.js で実行

Slide 17

Slide 17 text

17 例: ヘッダーのテキストを取得する 関数の中はブラウザで実行される。 DOM API が使える。 Node.js で実行

Slide 18

Slide 18 text

18 ブラウザ上で関数を実行する仕組み ● さっきと同じ ○ 1. Node.js 側: fn.toString() ○ 2. Node.js 側: それをブラウザに送信 ○ 3. ブラウザ側: const fn = eval(fnStr) ○ 4. ブラウザ側: fn() で実行 ● ブラウザ上で fn() が実行される!

Slide 19

Slide 19 text

19 用途② ネイティブコード判定

Slide 20

Slide 20 text

20 Function.prototype. toString() ソースコードが取り出せると言うけど ● 実は必ずしもそうではない ● 例: alert ○ 自分が書いた関数ではなく、組み込みの関数 ○ toString() するとどうなる?

Slide 21

Slide 21 text

21 組み込みの関数で toString() すると... 組み込み関数は 中身が見えないようになってる

Slide 22

Slide 22 text

22 応用: ネイティブコード判定

Slide 23

Slide 23 text

23 Function.prototype. toString() とはいえ ● 実用的な用途思いつかなかった ● 実用例調べたけどない ○ 何かに使えると思うんだけど... ○ 知ってる人いたら教えて下さい

Slide 24

Slide 24 text

24 Function.prototype. toString() 余談: core-js ● core-js の polyfill は JavaScript で書かれてるけど... ○ ネイティブコードであるかのように偽装してる

Slide 25

Slide 25 text

25 core-js のネイティブコード偽装 徹底して polyfill しててすごい

Slide 26

Slide 26 text

26 用途③ Dependency Injection

Slide 27

Slide 27 text

27 AngularJS の Dependency Injection ● AngularJS: Viewフレームワーク ○ 2009 年リリース、現在 EoL ○ 注意: 後継とされる Angular とはだいぶ別物 ■ 混同しないように! ● 引数を使い、Controller に Service を DI できる ○ Function.prototype.toString() が使われてる

Slide 28

Slide 28 text

28 例: AngularJS の Controller の定義

Slide 29

Slide 29 text

29 例: AngularJS の Controller の定義 (DI される) Service を表す引数

Slide 30

Slide 30 text

30 Dependency Injection のフロー ①toString() して関数のソースコードを取得

Slide 31

Slide 31 text

31 Dependency Injection ② 引数リストから $scope, greeter の 2 つの Service に依存してることを推測

Slide 32

Slide 32 text

32 Dependency Injection ② 引数リストから $scope, greeter の 2 つの Service に依存してることを推測 ③ランタイムが $scope, greeter を DI する

Slide 33

Slide 33 text

33 荒業

Slide 34

Slide 34 text

34 荒業すぎて minify すると壊れる

Slide 35

Slide 35 text

35 minify すると壊れる ● どういうことか ○ minify 前: ($scope, greeter) => {...} ○ minify 後: (a, b) => {...} ● Service 名が推測できなくなる ○ DI 失敗

Slide 36

Slide 36 text

36 回避策 1. 文字列で Service 名を埋め込む ○ `ctrl.$inject = ['$scope', 'greeter']` ○ 自分で書いてるコードなら文字列形式に書き換えできるが... ■ 3rd-party ライブラリ中のコードの書き換えは厳しい 2. 識別子だけ minify やめる ○ `minifyOption: { minifyIdentifiers: false }` ○ 弊社ではやってた

Slide 37

Slide 37 text

37 何故こうなってるのか ● 今だったら ○ bundle して、minify するのが当たり前 ○ minify すると壊れる、は考えられない ● 当時は bundler なかった ○ minify も今ほど気軽にできない ● 当時の時代背景故、こうなってる

Slide 38

Slide 38 text

38 用途④ お手製 template literal

Slide 39

Slide 39 text

39 実は...

Slide 40

Slide 40 text

40 荒業MAX な 応用例

Slide 41

Slide 41 text

41 漢は黙ってjQuery / @potato4d https://speakerdeck.com/potato4d/han-hamo-tutejquery?slide=35

Slide 42

Slide 42 text

42 まとめ ● Function.prototype.toString() でできること ○ 関数の転送 ○ ネイティブコード判定 ○ Dependency Injection ○ お手製 template literal ● 面白いことができるが、気軽に使うと大変なことに ○ 乱用、ダメ。ゼッタイ。