【javascript】type="module"の時にグローバル変数を作る方法


結論

window.globals = {変数名: 値}
は、javascript実行環境全体で使いまわすことができる。

そもそもの問題

type="module"でjavascriptを使っていると、「varを省略することでグローバル変数を作る」ことが出来ない。

だから、次のプログラムは動かない。

type="module"の苦悩
<html>
    <head>
        <script type="module">
        document.body = document.createElement("body");
        document.body.innerHTML = `
        <div id="カウンタ"></div>
        <div id="ボタンたち">
            <input type="button" value="++" onClick="画面.add(1)">
            <input type="button" value="--" onClick="画面.add(-1)">
            <input type="button" value="="  onClick="画面.print()">
        </div>
    `;
        画面 = { // ★
            i    : 0,
            add  : function(delta){this.i += delta;},
            print: function(){document.getElementById("カウンタ").innerHTML = this.i;}
        };
        画面.print();

        </script>
    </head>
    <body></body>
</html>

これをブラウザから表示すると、RefarenceErrorになる。
なぜならtype="module"の場合、varなどなしに変数を宣言できないからだ。

★の行をvar 画面 = {に代えると、最初こそ描画されるが、ボタンをクリックしたときに画面 not defined at HTMLInputElement.onclickと怒られる。
headタグ内でvarにて定義したローカル変数を、body以下の要素で利用しようとしたのだから当然だ。

ようするにtype="module"のスクリプト内で定義した変数を、同じファイル内の別の個所で利用しようとすると詰むのだ。
そもそもtype="module"は、グローバルスコープで動かない。

しかし抜け道がある。それこそがwindowオブジェクトの利用だ。

windowオブジェクトは、JavaScriptコードが動作しているWebブラウザのウィンドウまたはフレームを表すオブジェクトだ。
なので、ここにglobalsプロパティを勝手に追加し、window.globalsへグローバル変数とその値を記述した連想配列(=オブジェクト)を代入してしまえば、その内容は同じフレーム内のどこからでも取り出すことが出来るというわけだ。

ちなみに、参考2によれば、javascriptはそれがブラウザで実行されていようがNode.js上で実行されていようが、スクリプト実行前に一つ「Globalオブジェクト」と呼ばれるものを生成し、これは実行環境全体で共有されるそうだ。ブラウザで実行されるjavascriptにおいて、「Globalオブジェクト」とはwindowそのものである。

動作する例は次の通り。

type="module"でもグローバらせてくれるwindowさん(変更点は全5か所)
<html>
    <head>
        <script type="module">
        document.body = document.createElement("body");
        document.body.innerHTML = `
        <div id="カウンタ"></div>
        <div id="ボタンたち">
            <input type="button" value="++" onClick="window.globals.画面.add(1)"> // 変更点
            <input type="button" value="--" onClick="window.globals.画面.add(-1)">// 変更点
            <input type="button" value="="  onClick="window.globals.画面.print()">// 変更点
        </div>
    `;
        var 画面 = { // 変更点
            i    : 0,
            add  : function(delta){this.i += delta;},
            print: function(){document.getElementById("カウンタ").innerHTML = this.i;}
        };
        画面.print();
        window.globals = {画面:画面}; // 変更点
        </script>
    </head>
    <body></body>
</html>

See the Pen Untitled by 平田 智剛 (@17ec084) on CodePen.

参考

1.

2.