一言で要点を説明:GASの変数は、スクリプトが実行されるたびにリセットされます。
これは、JavaScriptの感覚でGASを書く際にハマりやすい落とし穴です。StackOverflowのこの投稿(https://stackoverflow.com/a/24732037)にもあるように:
Global variable will be evaluated at each execution of a script, so not just once every time you run your application. Global variables CAN be changed in a script…
調査の結果、実際にはグローバル変数だけでなく、すべての変数が実行時にリセットされることが判明しました。
その背景にある原理は、GASの実行環境であるV8ランタイムがステートレス(stateless)として設計されているためです。スクリプトが実行されるたびに環境が初期化され、大まかな流れとして、まずグローバルスコープのコードが実行され、その後メイン関数が実行されます。実行が終了するとすべてのメモリが解放されるため、すべての変数がリセットされると理解できます。
ステートレスの例(JavaScript)
ステートレスな関数は、外部の変数に依存せず、また外部の変数を変更しません。その実行結果は完全に内部変数によって決まります。
const c;
function add(a, b) {
return a + b;
}
ステートフルの例(JavaScript)
ステートフルな関数は、変数の値を保存または変更したり、外部変数に依存します。
let count = 0;
function increment() {
count += 1;
return count;
}
GASでの関数実行時のグローバルコードの挙動
以下のコードを例に説明します:
const test = 0;
function A() {
Logger.log("Function A executed, test = " + test);
}
function B() {
Logger.log("Function B executed, test = " + test);
}
function all() {
A();
B();
}
all()を実行する場合、GASの実行ロジックは以下のように動作します:
-
実行環境の初期化
スクリプトが実行されるたびに、グローバルスコープ内のコード(例:const test = 0;)が再実行され、初期化されます。 -
all()の実行
all()関数内でA()とB()が呼び出されます。これらの関数は同じ実行環境内で動作するため、グローバル変数testの値はA()とB()の間でリセットされることはありません。
つまり、スクリプトの実行中、グローバル変数は1度だけ初期化されます。ただし、スクリプトを再実行すると、グローバル変数は再度リセットされます。
結論
GASのグローバル変数はステートレスであり、スクリプト実行ごとにリセットされます。複数回の実行間で変数値を保持する必要がある場合、公式ドキュメントでは以下の使用を推奨しています:
- PropertiesService(プロパティストレージ)
- Googleスプレッドシートなどの外部データソース