JavaScriptの「禁じ手」:evalがスコープを破壊するメカニズムと、現代における正解
やあ。現場でコードを書いていて、`eval()`という関数に出会ったことはあるかい?
もし君が「なんか便利そうだな」と思って適当な文字列を放り込もうとしているなら、まずは手を止めてほしい。
`eval()`は、JavaScriptの世界における「パンドラの箱」だ。これを使うと、JavaScriptのエンジンが必死に構築したスコープの秩序が一瞬で崩壊する。今日は、なぜこの関数が「悪」とされ、現代のフロントエンド開発で徹底的に排除されるべきなのか、その核心を深掘りしていこう。
—
1. evalがスコープを「汚染」する仕組み
JavaScriptのスコープは、本来であればコンパイル(あるいは解析)の段階で静的に決定されるものだ。ところが、`eval()`はその性質上、実行時まで何が起きるか分からない。
これがどういう災いを招くか。端的に言えば、`eval()`は現在のスコープに直接介入できるんだ。
function dangerousCode() {
const localVariable = ‘隠された宝物’;
// evalの中で文字列としてコードを実行
eval(“var injectedVariable = ‘侵入者’;”);
console.log(injectedVariable); // => ‘侵入者’ が出力される!
console.log(localVariable); // => ‘隠された宝物’
}
dangerousCode();
// 本来、関数の外から内部のスコープをいじることは不可能だ。
// しかし、evalは現在の実行コンテキスト内でコードを解釈するため、
// その場で変数を定義し、スコープを強制的に書き換えてしまう。
見ての通り、`eval()`はスコープの壁をやすやすと飛び越える。これは最適化を行うブラウザのJSエンジン(V8など)からすれば悪夢だ。エンジンは「この変数はここで確定している」という前提で高速化を図るが、`eval()`があると「どこで変数が追加されるか分からない」ため、そのスコープ全体の最適化を諦めざるを得なくなる。結果、アプリケーション全体が劇的に遅くなるんだ。
—
2. 厳格モード(strict mode)による「隔離」
この無秩序な状況を救うために、ES5で導入されたのが`’use strict’;`だ。厳格モードでは、`eval()`の挙動が大きく制限される。
‘use strict’;
function strictScope() {
eval(“var secret = ‘誰にも見えない'”);
// 厳格モードでは、eval内で定義した変数はそのブロック内だけで生きる。
// 外側のスコープを汚染することが禁止されている。
console.log(typeof secret); // => ‘undefined’
}
strictScope();
厳格モードを使うと、`eval()`は独自のプライベートなスコープで実行されるようになる。外部への影響がなくなるため、セキュリティ上のリスクは多少軽減されるが、それでも「コードを文字列で実行する」という根本的なリスクは残る。
—
3. なぜ実務で使ってはいけないのか?
「スコープを汚すから」という技術的な理由以外にも、現場で避けるべき決定的な理由が2つある。
1. セキュリティ(コードインジェクション):
外部からの入力値(ユーザーの入力やAPIのレスポンス)をそのまま`eval()`に渡せば、悪意のある第三者が任意のスクリプトを実行できてしまう。これはXSS(クロスサイトスクリプティング)の温床だ。
2. デバッグの困難さ:
`eval()`で実行されたコードはソースマップが効かないことが多い。エラーが発生した際、スタックトレースには「anonymous」としか表示されず、どの行で何が起きたのか追跡不能になる。
—
4. 現場での賢い代替え案
もし、君が「動的にプロパティにアクセスしたい」という理由で`eval()`を使おうとしているなら、それは全くの遠回りだ。
const user = { name: ‘Alice’, age: 25 };
const key = ‘name’;
// × 絶対にやってはいけない
// eval(‘console.log(user.’ + key + ‘)’);
// ○ これが正しいモダンな書き方
console.log(user[key]); // => ‘Alice’
あるいは、JSONをパースしたいだけなら `JSON.parse()` を使うべきだ。もし本当に動的にコードを実行する必要がある(例えば、ブラウザ上で動くコードエディタを作っている等)なら、セキュリティを担保したサンドボックスライブラリ(`vm2`のブラウザ版や、`new Function`の限定的な利用)を検討するべきだろう。
—
シニアからの提言
JavaScriptの歴史において、`eval()`は「何でもできる魔法の杖」として君臨していた時代もあった。しかし、現代のフロントエンド開発においては、「予測可能性(Predictability)」こそが最大の正義だ。
コードが書かれた瞬間に挙動が定まり、ツールによって静的解析ができること。それが大規模アプリケーションを壊さずに運用するための鉄則だ。
もし君のコードベースに `eval()` が残っているなら、それは技術的負債という名の時限爆弾だ。今日の知識を武器に、ぜひ安全で、高速で、誰が読んでも挙動が明快なコードへと書き換えてみてほしい。
何かあればいつでも相談してくれ。コードは嘘をつかない、だが、`eval`は平気で裏切るからな。

コメント