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