📥

[JavaScript] Dynamic Importでevalを代替する

2021/09/26に公開

JavaScriptには、与えられた文字列をコードと解釈して実行するevalという関数があります。

外部から任意のコードを実行される可能性のある危険な処理であり、パフォーマンス的にも問題があります。
MDNでも「evalを使わないでください!」と書かれています。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/eval#eval_を使わないでください%25

MDNの記事では代替としてFunction()を使う方法が紹介されていますが、本記事では別の手法を紹介します。

方法

import()を使います。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports

const src = `
export function hello(name){
  console.log("Hello, " + name);
};
`;
const data = "data:text/javascript;base64," + btoa(src);
// ↓こっちもOK
// const data = "data:text/javascript;charset=utf-8," + encodeURIComponent(src);
const mod = await import(data);
mod.hello("world");
// → Hello, world

import()は基本的にファイルパスを引数に取りますが、ここにData URIを入れられることを利用し、文字列を変換して渡すことで、それをモジュールとして解釈させます。
上記の例では、srcの文字列をモジュールとしてインポートし、実行しています。

eval()と比べて安全なわけではないですが、日本語の紹介記事が見当たらなかったのでまとめてみました。
実用性は不明ですが、頭の片隅に置いておくと、何かの役に立つかもしれません。
…いや、やっぱり使わないかな…。

参考

https://stackoverflow.com/questions/57121467/import-a-module-from-string-variable
https://2ality.com/2019/10/eval-via-import.html

Discussion