JavaScript
jsnote

JavaScriptのES6のmoudleでimportした変数をFunction コントラクタの中で使う方法

背景

ブラウザで動くjavascriptエディター jsnoteを作っていた. Functionコンストラクタでユーザが入力したコードを実行できるようにした. ES6のモジュールで作った変数をそのエディタでよんでも実行できなくて困った.

問題

ブラウザでES6のmoduleでimportした変数をFunctionコントラクタの中で呼べない.
実行環境: Chrome ver63

import * as myapp from "./myapp/index.mjs"
myapp.sample() // OK
let code = "myapp.sample()"
new Function(code)() // ERROR

consoleでmyappが存在しないと言われて実行できない

原因

MDNによると同じjavascriptのファイル内に書いた変数はスコープが違うからFunctionの中で呼び出せない.

Function コンストラクタによる関数の生成は、生成コンテキストにクロージャを作りません。つまり常にグローバルスコープで作成します。これを実行すると、 Function コンストラクタの呼び出し元のスコープは入らず、自身のローカル変数とグローバル変数だけにアクセスできます。これは関数式のコードに eval を使うのとは異なっています。

MDNへのリンク

たとえ、varを使ってグローバル変数に入れても効かない.

import * as myapp from "./myapp/index.mjs"
myapp.sample() //  OK
var MYAPP = myappp
let code = "myapp.sample()"
new Function(code)() //  ERROR

対処法

windowのプロパティに入れてグローバル変数にすると使える

import * as myapp from "./myapp/index.mjs"
myapp.sample() //  OK
window.myapp = myapp
let code = "myapp.sample()"
new Function(code)() //  OK