背景
GoogleAppsScript がV8エンジン対応になって、class構文でextendsが使えるようになったけど、ファイルの読み込み順によっては使えない という話を聞いたので調査してみました。
問題点の確認
class AAA {
printMessage(text) {
console.log(text);
}
}
class BBB extends AAA {
}
function muFunc() {
const b = new BBB();
b.printMessage("あああー");
}
の実行結果は
[20-05-18 10:16:31:982 JST] あああー
だけど、(↓ BBBが先、AAAが後に定義されてる)
class BBB extends AAA {
}
class AAA {
printMessage(text) {
console.log(text);
}
}
function muFunc() {
const b = new BBB();
b.printMessage("あああー");
}
の実行結果は
ReferenceError: Cannot access 'AAA' before initialization(行 1、ファイル「コード」)
つまり、親クラスを先に定義しておかないとならない、と。
「1つの .gs ファイルで完結しているコード」なら、そのコードの上に親クラスを書けば解決しますが、
ファイル構成が増えて、親クラス子クラスが別ファイルになったときに困りそうです。
2023-10-31 追記
スクリプトエディタの仕様が変わったようで、最初に記事を投稿したときと状況が変わっていることに気づいたので補足投稿します。
結論としては 「ファイルの作成順」 ではなく 「ファイルの並び順」に従って、上から読み込まれていくので、クラス定義とかは上にしておこう になります。
古いエディタがどうだったか覚えていないのですが、現時点では下記の2つのキャプチャのように
- アルファベット順にファイルを並べ替える
- ファイル(の並び順を)を上下に移動する
ことが可能になっています。
並び順が影響することの確認コード
↑ このようにしてあるとして、
class BBB extends AAA {
}
class AAA {
printMessage(text) {
console.log(text);
}
}
function myFunc() {
const b = new BBB();
b.printMessage("あああー");
}
から、 myFunc()
を実行すると下記のエラーになります。
ReferenceError: AAA is not defined
(匿名) @ 1番目に作成.gs:1
これはわかりやすい。AよりBが先に定義されているからね。
この状態から下記のようにファイルの並び順を変えてみます。
(ファイルの中身は変えてません。並び順だけ変えた)
これで myFunc()
を実行すると正常に実行されます。
あああー
確かに過去の記事のように「作成順」なんて気にしてられないもんね。
「並び順」のほうが直感的。
問題があるとすると、この事情を知らない後任者が「アルファベット順にファイルを並べ替える」を実行してしまうと狂っちゃうことですかね。。。
(追記ここまで)
以下は初回の記事投稿時のもの
実験
ちゃんと動くやつ
新しいGoogleAppsScriptを作成します。
元からある コード.gs
をリネームして classA.gs
を作成します。
[ファイル] → [New] → [スクリプトファイル] で classB.gs
を作成します。
同じく myFunc.gs
を作成します。
この状態で myFunc()
を実行します。
実行結果は下記で、意図通り動いています。
[20-05-18 10:31:03:965 JST] あああー
並び順を変えてみる
ファイル名を下記のように変更してみます。意図としては「左カラムに並んでる順番に読み込まれてるのではないか」という仮説の検証です。
仮説が正しいとすると、AよりBが先に読み込まれるのでエラーになるはずです。
ところが実行結果は
[20-05-18 10:36:20:705 JST] あああー
でした。どうやら「ファイル名」ではないようです。
ここでピンと来たね
ファイルが生成された順番では?
新規にスクリプトを作成して、今度は classB.gs
→ classA.gs
→ myFunc.gs
の順番でファイルを作成します。
この状態で myFunc()
を実行するとエラー出た!
結論
ここまでの実験から、「ファイルの生成順に読み込まれる」ことがわかりました。(ただ「実はそれ以外の要因があって、今回はたまたま作成順だった」という可能性もあります)
GASでclassの継承をするには、下記のようにするとうまくいきそうです。
- 1つのgsファイル内に、親クラス、子クラスを定義する。
- 別のファイルの親クラス、子クラスを書く場合は、親クラスのgsファイルを先に生成する (すでに子が先に書かれていて親クラスのファイルを後から追加するときは、ファイルを新規作成して子クラスの中身を移動すればいい)