Upgrade to Pro — share decks privately, control downloads, hide ads and more …

あなたの知らない Function.prototype.toString() の世界

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for mizdra mizdra PRO
November 22, 2024

あなたの知らない Function.prototype.toString() の世界

JSConf JP 2024 の発表資料です。

---

JavaScript には Function.prototype.toString() という API があります。この API を使うと、関数本体のソースコードを文字列として取得できます。 一見すると何の使い道があるか分からないかもしれません。しかし、関数本体のソースコードを取得できるということは、実行時に関数のソースコードを静的解析できることを意味します。また、関数をシリアライズしてどこかに転送した後、デシリアライズして実行するといったことも可能です。この特徴は、JavaScript に大きな力をもたらします。 このトークでは、 Function.prototype.toString() はどんな API なのか、どういう使い道があるのか、世の中のライブラリで利用されている実用的なものから、狂った使い方まで紹介します。

- リモート関数 (puppeteer の page.evaluate())
- ネイティブコード判定
- tempalte literal を使わない複数行文字列リテラル
- etc...

Avatar for mizdra

mizdra PRO

November 22, 2024
Tweet

More Decks by mizdra

Other Decks in Technology

Transcript

  1. 6 Function.prototype. toString() どんな API? • 関数のソースコードを取り出せる API • 関数

    (例: add) に対して add.toString() を呼び出す ◦ add 関数のソースコードが得られる
  2. 18 ブラウザ上で関数を実行する仕組み • さっきと同じ ◦ 1. Node.js 側: fn.toString() ◦

    2. Node.js 側: それをブラウザに送信 ◦ 3. ブラウザ側: const fn = eval(fnStr) ◦ 4. ブラウザ側: fn() で実行 • ブラウザ上で fn() が実行される!
  3. 20 Function.prototype. toString() ソースコードが取り出せると言うけど • 実は必ずしもそうではない • 例: alert ◦

    自分が書いた関数ではなく、組み込みの関数 ◦ toString() するとどうなる?
  4. 24 Function.prototype. toString() 余談: core-js • core-js の polyfill は

    JavaScript で書かれてるけど... ◦ ネイティブコードであるかのように偽装してる
  5. 27 AngularJS の Dependency Injection • AngularJS: Viewフレームワーク ◦ 2009

    年リリース、現在 EoL ◦ 注意: 後継とされる Angular とはだいぶ別物 ▪ 混同しないように! • 引数を使い、Controller に Service を DI できる ◦ Function.prototype.toString() が使われてる
  6. 32 Dependency Injection ② 引数リストから $scope, greeter の 2 つの

    Service に依存してることを推測 ③ランタイムが $scope, greeter を DI する
  7. 35 minify すると壊れる • どういうことか ◦ minify 前: ($scope, greeter)

    => {...} ◦ minify 後: (a, b) => {...} • Service 名が推測できなくなる ◦ DI 失敗
  8. 36 回避策 1. 文字列で Service 名を埋め込む ◦ `ctrl.$inject = ['$scope',

    'greeter']` ◦ 自分で書いてるコードなら文字列形式に書き換えできるが... ▪ 3rd-party ライブラリ中のコードの書き換えは厳しい 2. 識別子だけ minify やめる ◦ `minifyOption: { minifyIdentifiers: false }` ◦ 弊社ではやってた
  9. 37 何故こうなってるのか • 今だったら ◦ bundle して、minify するのが当たり前 ◦ minify

    すると壊れる、は考えられない • 当時は bundler なかった ◦ minify も今ほど気軽にできない • 当時の時代背景故、こうなってる
  10. 42 まとめ • Function.prototype.toString() でできること ◦ 関数の転送 ◦ ネイティブコード判定 ◦

    Dependency Injection ◦ お手製 template literal • 面白いことができるが、気軽に使うと大変なことに ◦ 乱用、ダメ。ゼッタイ。