GoogleAppScriptでevalしたい

GoogleAppScriptにもeval()はあるので、普通にeval(expression)すれば良いだけの話だが
他のスコープで実行するeval(expression)を自分のスコープに適用したい場合、eval.call(this, expression)をする必要があった。

初期のコード:evalのスコープと、その結果を参照するスコープが同じ

以下のコードは問題なく動く。

var exp = "var MyModule = {}; MyModule.TestClass = function() { return { \"sayHello\": function() { return \"this is a test.\"; } } };";
eval(exp);

var inst = new MyModule.TestClass();
Logger.log(inst.sayHello()); // => "this is a test."

次のステップのダメだったコード:そのままeval()の部分を別スコープに移動

そもそも別スコープに持って行きたかったのはUrlFetchAppを使って外部のJavaScriptをテキストで取得したものを
GoogleAppScriptのコードとして実行したかったという背景がある。
なので、以下のようなコードを当初書いて、動かなかった。

/**
 * LibraryLoader.gas
 */

var LibraryLoader = LibraryLoader || {};

LibraryLoader.loadExternalJavaScript = function(url) {
  var exp = UrlFetchApp.fetch(url, {"method": "GET"}).getContentText();
  eval(exp);
};
/**
 * SomeProgram.gas
 */

LibraryLoader.loadExternalJavaScript("https://somehost/somefile.js"); // このsomehost/somefile.jsに先の定義分が書かれている想定
var inst = new MyModule.TestClass(); // MyModuleが見つかりません例外
Logger.log(inst.sayHello());

最終的なコード:eval呼び出し時にスコープを明示してやる

/**
 * LibraryLoader.gas
 */

var LibraryLoader = LibraryLoader || {};

LibraryLoader.loadExternalJavaScript = function(url) {
  var exp = UrlFetchApp.fetch(url, {"method": "GET"}).getContentText();
  eval.call(this, exp);
};
/**
 * SomeProgram.gas
 */

LibraryLoader.loadExternalJavaScript("https://somehost/somefile.js"); // このsomehost/somefile.jsに先の定義分が書かれている想定
var inst = new MyModule.TestClass();
Logger.log(inst.sayHello()); // => "this is a test."

なぜ上記コードで呼び出し元でMyModuleが見つけられるようになったか、おそらくだがこちらのページに解説されているthisの意味からすると当然なのだろう。

JavaScriptのthis、難しい。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です