JavaScript
Node.js
サンプルコード
eval
クロージャ

[JavaScript][Node.js] eval を クロージャ で置き換えるサンプル

eval は文字列をコードとして評価して実行する強力な仕組みです。
特にプログラムを動的に書いてそれを実行するプログラム(コードジェネレータの一種)を記述する際に重宝していました。

eval-sample.js
var fs = require('fs');
for (let i=0; i<10; i++) {
    /* プログラムを動的に生成 */
    var sub_program  = "function printValue() {¥n";
    sub_program     += "    console.log('value is " + i + "');¥n";
    sub_program     += "}¥n";
    sub_program     += "module.exports.exec = printValue;¥n";

    /* ファイルに保存 */
    var js_path = "./" + i + "_subpg.js"; // ./i_subpg.js
    fs.writeFile(js_path, sub_program, function(err) {
        if (err) { throw err; }
    });

    /* ファイルに記述したプログラムを eval で実行 */
    eva("var exec_program = require(" + js_path + "); exec_progmram.exec();");
    // value is 0
    // value is 1
    // value is 2
    // ...
    // value is 9
}

しかし、eval には呼び出し元の権限でコードが実行されるセキュリティ上のリスク、及びパフォーマンスが悪い(処理が遅い)という欠点があります。

そこで、 eval ではなく、クロージャでプログラムの動的生成と実行を置き換えます。

closure-sample.js
var fs = require('fs');
for (let i=0; i<10; i++) {
    /* プログラムを動的に生成 */
    var sub_program  = "function printValue() {¥n";
    sub_program     += "    console.log('value is " + i + "');¥n";
    sub_program     += "}¥n";
    sub_program     += "module.exports.exec = printValue;¥n";

    /* ファイルに保存 */
    var js_path = "./" + i + "_subpg.js"; // ./i_subpg.js
    fs.writeFile(js_path, sub_program, function(err) {
        if (err) { throw err; }
    });

    /* ファイルに記述したプログラムをクロージャで実行 */
    let execProgram = execProgramCreator(js_path);
    execProgram();
    // value is 0
    // value is 1
    // value is 2
    // ...
    // value is 9
}

function execProgramCreator(js_path) {
    return function execProgram() {
        var exec_program = require(js_path);
        exec_program.exec();
    };
}

クロージャを使うと、クロージャ生成時の変数の状態(上記のサンプルでは js_path )をクロージャ実行時まで保持することができますので、グローバルを汚染することなく状態の保持を行うことができるメリットもあります。