GASの基礎知識

## はじめに
たまに業務でGASを書いたりするのですが、書くために勉強したことを記事にまとめておこうと思います。まとめる内容としては、GASとは何かからスプレッドシートの使い方ぐらいまでをまとめます。Gmailやカレンダーの連携は記載しません。

## GASの基礎知識
### GASとは
- Google Apps Script、通称GAS（ガス）と呼ばれるプログラミング言語
- Google社が提供している
- JavaScriptベースで作られている
    - 全く一緒ということではなく、Webページを作成するなどはできない

### GASの特徴
- Google Appsと連携できること
    - 連携できるGoogle Apps
        - Gmail
        - Google Calender
        - Google Hangout
        - Google Document
        - Google Spreadsheet
        - Google Forms
        - Google Slides
        - Google Sites
        - Google Map
        - Google Language
- Google社のクラウドサーバーで動いている。メリットは以下の通り。
    - 環境構築がいらない
    - 定期実行が容易

### GASを使うために必要なもの
- Googleアカウント
- ブラウザ
- インターネットに接続できるPC

### GASの始め方
GASを始める方法は主に二つ

- Google Driveから作成する方法
    - ![スクリーンショット 2022-01-15 1.00.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/1371c093-cf0d-ceb4-0cef-c8fb6ce453a1.png)
- スプレッドシート等から作成する方法
    - ![スクリーンショット 2022-01-15 1.02.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/23d43af3-5c08-64cd-3415-3439f3662efd.png)

### プロジェクトとスクリプト
#### スクリプト
GASで記述されたプログラムのこと。上の画像を例にとると、コード.gsになる。

#### プロジェクト
プロジェクトとは、単一もしくは複数のスクリプトで構成されたもの。


##### スタンドアロンスクリプト
プロジェクト自体を直接Googleドライブに保存されたもの。他の人に見つからないからいい。


##### コンテナバインドスクリプト
スプレッドシートなどに紐づく形で保存されたもの

### ログ
GASにはスクリプトの動作を確認するために、ログという機能がある。ログ機能は、以下のように使う。
1. **```Logger.log(値);```を記入する**
今回はこのように記入してみる。

```javascript:log.gs
function myFunction() {
    Logger.log("Hello world");
}
```
2. **スクリプトを保存する**
それっぽいボタンを押して保存する。
![スクリーンショット 2022-01-15 1.07.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/941e9e38-726e-790d-4fa7-bf64579f3e93.png)


3. **スクリプトを実行する**
それっぽいボタンを押して実行する
![スクリーンショット 2022-01-15 1.07.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/f59d5eb6-b396-c250-3ab0-db3cf5fa692a.png)


4. **ログを確認する** 
エディタ画面の実行ログで確認できる
![スクリーンショット 2022-01-15 1.10.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/34dd4e95-7699-00e4-6984-e5439eac54bb.png)


### 基本形
GASの基本形は、以下の通り。文末にセミコロンを忘れない。

```javascript
function 関数名 () {
    処理;
}
```

### 変数の宣言
変数を定義する際、変数を宣言してから代入する場合と、宣言と代入を同時に行う場合がある。

```javascript
function myFunction() {
    // 変数を宣言してから代入する場合
    var a;
    a = 10;
    Logger.log(a); // 10

    // 宣言と代入を同時に行う場合
    var b = "GAS";
    Logger.log(b); // "GAS"
}
```

### 変数と定数
- 変数：上書きが可能。定義する際に `var`　を用いる。
- 定数：上書きが不可能。定義する際に `const` を用いる。

```javascript
function myFunciton() {
    // 変数
    var x = 10;
    x = 14;
    Logger.log(x); // 14

    // 定数
    const y = 5;
    y = 50;
    Logger.log(y); // 5
}
```

### データ型

| データ型 | 説明 | 例 |
| -------- | -------- | -------- |
| 数値型（Number）     | 整数値や浮動小数点。  | 5, 1.08     |
| 文字列型（String）     | 文字列。ダブルクオーテーション（"）などで囲む。   | "GAS", 'test'     |
| 真偽値    |　真と偽のどちらかの値をとるデータ型。   | true, false     |
| null     | 値がないことを表す値  | null    |
| 配列型（Array）    | インデックスをキーとするデータの集合   | [1,2,3], ["array", true]     |
| オブジェクト型（Object）    | プロパティをキーとするデータの集合   | {apple:"りんご", banana:"バナナ"}, {x:10, y:20, z:30}   |

### 配列
配列は、複数のデータの集合。それぞれのデータには番号が振られていて、1番最初のデータは**0**でアクセスすることができる。アクセスの仕方は、配列名[インデックス]。

```javascript
function myFunction() {
    var array = [25, 30, 35, 40];
    Logger.log(array[2]); // 35
}
```

要素を指定して、代入することも可能。

```javascript
function myFunction() {
    var array = [25, 30, 35, 40];
    array[2] = 10;
    Logger.log(array); // [25, 30, 10, 40]
}
```

#### 2次元配列
２次元配列は、配列の要素が配列のことをさす。アクセスの仕方は、基本的に１次元のものと変わらない。

```javascript
function myFunction() {
    var arrays = [[1,2,3],[4,5,6],[7,8]];

    Logger.log(arrays[0]); // [1,2,3]

    // 要素の配列の中身を取得するには、2回アクセスすればいい
    var array = arrays[1];
    Logger.log(array[2]); // 6
    Logger.log(arrays[1][2]); // 6
}
```

### オブジェクト
オブジェクトは、複数のデータの集合。配列の場合は要素にアクセスするためにインデックスを用いたが、オブジェクトはプロパティを用いる。アクセスの仕方は、オブジェクト名['プロパティ']、もしくはオブジェクト名.プロパティ。

```javascript
function myFunction {
    var person = {name:"Bob", sex:"male", age:10};

    Logger.log(person.name); // "Bob"
    Logger.log(person['Bob']); // "Bob"
}
```

プロパティを指定して、代入することも可能。

```javascript
function myFunction() {
    var person = {name:"Bob", sex:"male", age:10};

    person.name = "Kevin";
    Logger.log(person.name); // "Kevin"

    person['age'] = 20;
    Logger.log(person['age']); // 20
}
```

### if 文
条件分岐をするときに用いられるのが、`if`文。GAS(JavaScript)の形は、以下の通り。

```javascript
function myFunction() {
    var age = 15;

    if (age < 20) {
        Logger.log("お酒は飲んではいけません。");　// お酒は飲んではいけません。
    }
}
```

複数の条件を使いたいときは、`if...else`や、`else if`を使う。

```javascript
function myFunction() {
    var x = 12;

    if (x <= 5) {
        Logger.log("xは5以下です");
    } else if (x <= 10) {
        Logger.log("xは10以下です");
    } else {
        Logger.log("xは10より大きいです");
    }

    // "xは10より大きいです"
}
```

### 比較演算子と論理演算子
#### **比較演算子**
`if`文などの条件式で使う、比較のための演算子のことを、比較演算子という（例：<など）。今回は一部を紹介。

| 演算子 | 説明 |
| -------- | -------- | 
| ==     | 等しいかどうかを調べるときに使う     | 
| !=     | 等しいくないかどうかを調べるときに使う     | 


#### **論理演算子**
`if`文などの条件式で、複数の条件式を使えるようにする演算子のことを、論理演算子という。

| 演算子 | 説明 |
| -------- | -------- | 
| &&     | かつ     | 
| \|\|    | または     | 
| !    | 否定     | 

具体的な使い方は、以下の通り。

```javascript
var x = 5, y = 10;

if (x >= 5 && y >= 5) {
    Logger.log("xもyも5異常です。")
}
```


### for文
繰り返し処理を行いたいときに使うのが```for```文。繰り返し処理を行う、他の方法として```while```がある。今回は省略する。

```javascript
function myFunction() {
    var array = [25, 30, 35, 40];

    for (var i = 0; i < array.length; i++) {
        Logger.log(array[i]);
    }
}
```

#### for...of と for...in
`for`文では、上記の方法以外で繰り返し処理を行うことが可能。

```javascript
function myFunction() {
    // 配列の場合
    var array = [25, 30, 35, 40];

    for (var num of array) {
        Logger.log(num);
    }

    // オブジェクトの場合
    var fruits = {apple:"りんご", banana:"バナナ"}

    for (var kudamono in fruits) {
        Logger.log(kudamono);
    }

    for (var kudamono in fruits) {
    Logger.log(fruits[kudamono]);
    }
}
```

### GASの関数
GASは最初からmyFunctionという関数が用意されているが、他の関数を定義することが可能。新たに宣言する関数の基本形は、以下の通り。
#### **引数を取らない場合**

```javascript
function 関数名 () {
    処理;
}
```

具体例

```javascript
function myFunction() {
    hello(); // Hello
}

function hello() {
    Logger.log("Hello");
}
```

#### **引数をとる場合**

```javascript
function 関数名 (引数１,引数２,...) {
    処理;
    return 戻り値;
}
```

具体例

```javascript
function myFunction() {
    Logger.log(add_number(3,4)); // 7
}

function add_number(x,y) {
    return x + y;
}
```

### グローバル領域
関数外の領域を、グローバル領域という。ここに記述された内容は、関数内に記述されたものより先に実行される。

```javascript
Logger.log("1番");

function myFunction() {
    Logger.log("2番");
}

Logger.log("3番");
```

実行結果
`1番 `
`3番 `
`2番`

## スプレッドシート
### スプレッドシートを取得する
スプレッドシートを取得する方法は、以下の3つ。

- アクティブなスプレッドシートを取得する
- URLを指定して取得する
- IDを指定して取得する

具体例

```javascript
// コンテナバインドスクリプトであれば、これで取得できる
var spreadsheet_1 = SpreadsheetApp.getActiveSpreadsheet();

// URLを使って取得できる
var url = 'https://docs.google.com/spreadsheets/d/xxxxxx/edit#gid=0';
var spreadsheet_2 = SpreadsheetApp.openByUrl(url);

// IDを使って取得できる
var id = 'xxxxxx';
var spreadsheet_3 = SpreadsheetApp.openByID(id);
```

取得したスプレッドシートを使い、シートを取得することができる。

```javascript
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();

// シート名で取得する
var sheet = spreadsheet.getSheetByName('シート名');

// 複数のシートを取得する
// データは配列型
var sheets = spreadsheet.getSheets(); 
```

スプレッドシート->シートの順に取得するのは、あまり良くないらしい。
一気に取得する方法が以下。

```javascript
// アクティブなシートを取得する
var active_sheet = SpreadsheetApp.getActiveSheet();

```


### シートのデータ範囲を取得する
シートのデータ範囲を取得する際は `getRange()` を使う。

```javascript
// データ範囲を取得するために、アドレスを使う場合
// アドレスは、A2のような行列のインデックスを組み合わせたもの
sheetオブジェクト.getRange(アドレス)

// データ範囲を取得するために、行番号、列番号を使う場合
sheetオブジェクト.getRange(行番号,列番号[,行数,列数])
```

具体例

```javascript
function myFunction() {
    var sheet = SpreadsheetApp.getActiveSheet();

    // セルを指定
    Logger.log(sheet.getRange('A2').getA1Notation()); // A2
    Logger.log(sheet.getRange(2,1).getA1Notation()); // A2

    // 範囲を指定
    // アドレスを使う場合は、'左上のセルのアドレス:右下のセルのアドレス'で指定する
    Logger.log(sheet.getRange('A2:C4').getA1Notation()); // A2:C4
    Logger.log(sheet.getRange(2,1,3,3).getA1Notation()); // A2:C4

    // 行と列全体を指定
    Logger.log(sheet.getRange('A:A').getA1Notation()); // A:A
    Logger.log(sheet.getRange(1,1).getA1Notation()); // '1:1'
}
```

範囲はわからないけど、データ範囲全体を取得したい場合は`getDataRange()`を使う。

```javascript
sheetオブジェクト.getDataRange()
```

最終行や最終列の番号を取得する方法もある。

```javascript
function myFunction() {
    var sheet = SpreadsheetApp.getActiveSheet();
    Logger.log(sheet.getName()); // シート1

    // データがある最終行の番号を取得
    var row = sheet.getLastRow();
    Logger.log(row); // 4.0

    // データがある最終列の番号を取得
    var column = sheet.getLastColumn();
    Logger.log(column); // 3.0
}

```

### 値を取得・入力する
今回は以下のようなシートを用意して、試してみる。

![スクリーンショット 2022-01-15 1.27.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/846718b0-978f-5884-e081-97fd3026c386.png)

#### **値を取得する際は、`getValue()/getValues()`を使う**
値を取得する際は、データを取得する範囲を指定して、`getValue()/getValues()`を使う。

- `getValue()` : データが1つ
- `getValues()` : データが複数

具体例

```javascript
function myFunction() {
    var sheet = SpreadsheetApp.getActiveSheet();

    // セルのデータを取得するときは getValue() を用いる
    Logger.log(sheet.getRange('A2').getValue()); // Tom


    // 指定した範囲のデータを取得するときは getValues() を使用する
    Logger.log(sheet.getRange('A3:C4').getValues()); // [[John, male, 28.0], [Emma, female, 31.0]]
}
```

#### **値を入力する際は、`setValue()/setValues()`を使う**
値を取得する際は、データを取得する範囲を指定して、`setValue()/setValues()`を使う。

- `setValue()` : データが1つ
- `setValues()` : データが複数

具体例

```javascript
function myFunction() {
    var sheet = SpreadsheetApp.getActiveSheet();

    // セルにデータを入力するときは setValue() を用いる
    sheet.getRange('A5').setValue('Anthony');
    Logger.log(sheet.getRange('A5').getValue()); // Anthony

    // 指定した範囲にデータを入力するときは setValues() を使用する
    sheet.getRange('B5:C5').setValues([['male', 34]]);
    Logger.log(sheet.getRange('A5:C5').getValues()); // [[Anthony, male, 34.0]]
}
```


### シートに行を追加する
`Sheetオブジェクト.appendRow()`で行を追加することができる。

具体例

```javascript
function myFunction() {
    var sheet = SpreadsheetApp.getActiveSheet();

    // データを追加する
    sheet.appendRow(['Luna', 'female', 30]);

    // 式も代入できる
    sheet.appendRow([null, null, '=AVERAGE(C2:C6)']);
}
```

![スクリーンショット 2022-01-15 1.33.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/324c46f0-2cd0-5049-9d0a-a5b024ba0478.png)

### セル範囲を並び替える
`Rangeオブジェクト.sort(列番号)`で並べ替えることができる。

```javascript
function myFunction() {
    var sheet = SpreadsheetApp.getActiveSheet();

    // 範囲を取得する
    var range = sheet.getRange('A2:C6');

    // 性別を降順で並び替え
    range.sort([
        {column: 2, ascending: false}
    ]);
}
```

**sort前↓**
![スクリーンショット 2022-01-15 1.35.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/1242cb6f-f598-8d58-5596-61752784346a.png)

**sort後↓**
![スクリーンショット 2022-01-15 1.36.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/c2dfa796-10c7-01ed-15af-63b0f46e6031.png)


## さいごに
今回はGASの使い方をまとめてみました。今後は、Gmailやカレンダーの使い方もまとめて記事にしてみようかなと思います。