あなたの知らない Function.prototype.toString() の世界
by
mizdra
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
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 ● 面白いことができるが、気軽に使うと大変なことに ○ 乱用、ダメ。ゼッタイ。