【実務・中級編】 eval関数がスコープに与える影響 – JavaScript実践ガイド

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`は平気で裏切るからな。

コメント

タイトルとURLをコピーしました