GASライブラリの、Global Object

GASのライブラリ機能

GASには、あるプロジェクトを他のプロジェクトからライブラリとして読み込む、という機能があります。

このとき、読み込まれるプロジェクト側では:

  1. グローバル空間で、
  2. function宣言文によって定義された関数だけが、

公開されます。

読み込み側へは、利用者側で設定した名前のグローバルオブジェクトに公開された関数が格納されるという形で、公開されます。

Javascriptでライブラリセットを構築するとき、グローバル空間を汚さないように単一のオブジェクトにすべてを格納することが多いかと思いますが、これと似ています。

Where is this?

で、気になったのが、「ライブラリにとってのグローバル空間ってどこだろう」。

ライブラリは、ロードされ、初回の実行コンテキスト(目的関数の起動ではなく、On Loadでの実行。なにか呼び名があるんでしょうか?)のときに認識しているグローバル名前空間(グローバルオブジェクト)は、利用者側のオブジェクトのなかに納まってしまいます。

ライブラリからみると、最初自分が「ここがグローバル」と思っていたところが、いつのまにか「1オブジェクトのなか」に変化してしまうんでしょうか。

Jasmine & Rajah による実験

と、いうことで、実際にコードを動かして試してみました。
Rajahを使って、Jasmineを走らせながら実験を。

書籍:「テスト駆動JavaScript」のなかで、「学ぶためのテスト」として紹介されていた方法です。

jasmineを使って、気になることをまず仕様として記述し、成功・失敗を繰り返しながら、正しい仕様だけが記述されたSpecファイル(つまりすべてパスする仕様)をつくってゆくやりかたです。

試して学んだことが仕様として残るので、あとで見直すにせよ、他の環境で再実験するにせよ、よい資産になると思います。

ソースコードとSpecコード


眠い。
おやすみなさい。


--- 翌日 ---

結果

とりあえず、結果から。

ユーザーコードと、ライブラリコードは、それぞれ別のグローバルオブジェクトを持ち別々の名前空間で実行されています。

ユーザー空間からライブラリ関数を呼び出したときに、コンテキストが切りかわるようです。

var なしの変数

ライブラリ関数のなかで、varなしの変数に値を代入しても、ユーザーのグローバル空間にはその変数を見つけることができません。

即時実行関数からのthis

ライブラリ呼び出し前のユーザー空間で:

USER_THIS = (function () { return this; })();

として、ライブラリ関数の中で:

GASLIB_THIS = (function () { return this; })();

として、ふたつを比較しても一致しません。
デバッガーで中を覗いてみると、それぞれに別のメンバーが存在していました。

さきの、varなしの変数もこの GASLIB_THIS のなかに見つかります。


結論

ライブラリに提供されるグローバル名前空間は、ユーザーのグローバル名前空間から切り離されている。

GASLIB_setMyGlobalObject( this );

などとして明示的に渡さない限り、相互にグローバルオブジェクトを参照する方法はない。





Comments