ノンプロ研 GAS初級講座21期 補講 #4-5

# 概要
**ノンプログラマーのためのスキルアップ研究会 GoogleAppsScript初級講座**
第4回「オブジェクト」
第5回「スプレッドシート・シート・セルの操作」
についての**非公式**の補講記事です。
21期講師のTaitoが執筆しています。

:::note warn
オブジェクト周りの話は用語の取り扱いが難しく、正確に書き切れる自信がありません。
用語について混乱があれば、都度ご質問くださいませ。
:::

https://plannauts.co.jp/nonproken/

### 調べ方
講座内でちらっと触れましたが
この回以降は`如何にオブジェクトのメソッドを効率よく探すか`が重要になってきます。
構文は理解した。あとは辞書を引くだけ。
という状態が理想的ですね。

辞書・リファレンスは以下の2サイトを参考にしましょう。

Google Apps Script REFERENCE: (Google公式)
https://developers.google.com/apps-script/reference
JavaScript | MDN: (Javascript準公式)
https://developer.mozilla.org/ja/docs/Learn/JavaScript

# 第4回 オブジェクト

### ここだけおぼえるポイント
- { プロパティ: 値 }
    - { key: value }
- 値はプロパティを指定して参照する(取り出す)
    - ドット.記法はシンプル
    - プラケット["記法"]は変数の使用ができる
- 値に関数が入る場合は`メソッド`と呼ぶ
- 実は、GASで扱うすべてのデータはオブジェクトになっている
    - "hoge" ← Stringオブジェクト
    - 123 ← Numberオブジェクト
    - [1, 2, 3] ← Arrayオブジェクト
    - SpreadsheetApp ← トップレベルオブジェクト
    - console ← Javascriptの組み込みオブジェクト
- `オブジェクトに対してメソッドを呼び出していく`のが、GAS操作の基本

### 基本構文
```javascript
const obj1 = { name: "Bob", age: 25 };
// プロパティ名は自動で文字列になるので"クォーテーション"は不要
// プロパティの追加・更新
obj1.favorite = "apple";
obj1["name"] = "Tom";

// 改行したほうが見やすいですね ,を忘れずに
const obj2 = {
  height: 10,
  width: 20,
  getArea() { // メソッド
    return this.height * this.width; // ↑のプロパティを参照
  },
  setHeight(num) { // メソッドには引数も渡せる
    this.height = num;
  }
}
// メソッドの追加は関数リテラル
obj2.メソッド名 = function() {
  // 処理
}
```

オブジェクトは
- 文字列や数値と同じ`データ型`である
- かつ、`すべてのデータはオブジェクト`でもある
- プログラミング用語では「オブジェクト」は更に広い意味を持つ

と、多義性に満ちた概念です。
ややこしくて、GAS初学者が最初につまずきやすいポイントです。
自分も最初は全然理解できませんでした。今も怪しいです。

第4回では
「データ型としてのオブジェクト」
「プロパティをキーとしたデータ集合としてのオブジェクト」
の話をしていました。
ひとつひとつ、ゆっくりモノにしていきましょう。

### for..in文について
オブジェクトの要素を列挙する場合は、for..in文を使います。
```javascript
const obj = {name: "Bob", age: 25};
for(const key in obj) {
  console.log(key);
  // name→age プロパティが順に出力
  console.log(obj[key]); // ブラケット記法
  // Bob→25 値が順に出力
}
```
for..文というのは、`反復可能なデータの全要素をループする`制御構文です。
for..of文もそうでしたね。
実は、配列はオブジェクトでもあるのでfor..in文でも書けます。
```javascript
const array = [1, 2, 3];
for (const index in array) {
  console.log(index);
  // 0→1→2 // インデックスが順に出力 (文字列として)
  console.log(array[index]);
  // 1→2→3 // 値が順に出力
}
```
配列ではfor..of文を使います。ただ、
- オブジェクトは`プロパティ`をキーとしたデータの集合
- 配列は`インデックス`をキーとしたデータの集合

この構造が似ていることを理解しておきましょう。
配列⇔オブジェクトを変換すること、よくあります。そういう時に役に立ちます。


### メソッドについて
基本形はこちらの`メソッド定義`です。
```javascript
const obj = {
  メソッド名() {
    // 処理
  }
}
obj.メソッド名(); // 実行
```
上記は簡略化された書き方(糖衣構文)で、実際には以下のように`関数リテラルの代入`が行われています。
```javascript
const obj = {
  メソッド名: function() {
    // 処理
  }
}
```
ここで関数リテラルと聞いて`アロー関数`を思い出すかもしれませんが、
アロー関数でメソッドを書いてはいけません。
理由は難解です！以下はいちおうの参考例ですが飛ばしてOKです。
```javascript
const person = { name: 'Bob' }

// 通常の関数リテラルで定義
person.greet1 = function () {
  console.log(`My name is ${this.name}`);
}
// 同じ処理をアロー関数で定義
person.greet2 = () => console.log(`My name is ${this.name}`);

function myFunction() {
  this.name = 'Alice'; // myFunctionのプロパティ

  person.greet1(); // My name is Bob
  // 通常の関数リテラルでは、thisはメソッドを含むオブジェクトを参照します

  person.greet2(); // My name is Alice
  // アロー関数では、thisはオブジェクトの外側を参照する特性があります
}
```
このほか、オブジェクトについて学んでいくと
- 値渡しと参照渡し
- クラスとインスタンス
- プロトタイプ
- オブジェクト指向

などなど、一筋縄ではいかない概念がたくさん出てきます（GAS中級講座の対象です）。
理解しなければ実務で使えない…というわけではありませんが、
- なぜオブジェクトの中にメソッド(関数)を書く必要があるのか？
- なぜGASのすべてのデータはオブジェクトになっているのか？

深掘りしてみたい方は、学んでみるのも面白いかもしれません。

https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics

* * *
# 第5回 スプレッドシート・シート・セルの操作
いやいや、ややこしいオブジェクトの話なんてやめましょう！
よく分かんなくても使えるのがオブジェクトのいいところです！
スプレッドシートでオブジェクトをがんがん使い倒していきましょう。

### ここだけおぼえるポイント
- スプレッドシートは操作したい対象毎にオブジェクトがある
    - Spreadsheet スプレッドシートファイル
    - Sheet スプレッドシート内の各シート
    - Range シート内の範囲
    - Value 範囲から取得した値
- 上から順番につかんで操作する
    - メソッド1回呼び出し毎に変数に入れてもいいし、繋げて書いてもいい
```javascript
// 1つずつ変数に入れる
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet(); // 後で使いたければ変数に入れておきましょう
const range = sheet.getDataRange();
const values = range.getValues();

// 繋げて書く(メソッドチェーン)
const values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
```
### アクティブとは
コンテナバインドスクリプトでは、紐づけられたスプレッドシートが`アクティブ`になります。
```javascript
const ss = SpreadsheetApp.getActive(); // getActiveSpreadsheet()と同じ
// 紐づいたスプレッドシートが取得できる
// スタンドアロンスクリプトで↑を書くとエラーになります IDかURLで取りましょう
```
スプレッドシートを取得した後の`アクティブなシート`は文脈によって対象が変わってしまいます。
```javascript
const sheet = ss.getActiveSheet();
// コンテナバインドなら、今開いているシート
// スタンドアロンなら、一番左側のシート
```
注意しましょう。
このように、シートの指定には苦労がつきものですが、
- シート名で指定
- インデックスで指定
- アクティブで指定

どれも一長一短で、完ぺきな方法はありません。運用でカバーしましょう！

### Range
範囲指定はgetDataRange()だけ使えばOKとお伝えしましたが
- シートの1行目に空白がある
- セルが結合されている
- シートの中に複数のテーブルがある

などの場合、途端に役立たずになります。
（このようなシートを非構造化データと呼びます。第6回で取り扱います）

また特定のセルのみに値を書き込みたい場合は
アドレスでセル指定の方が効率的なので、状況に応じて使い分けましょう！
getRange()は、2パターンの引数を理解しておけばOKです。
```javascript
sheet.getRange(アドレス文字列);
sheet.getRange(開始行, 開始列, 取得行数, 取得列数); // 行数列数は省略可

sheet.getRange('A1:C3'); // A1からC3セルまで
// 同じ
sheet.getRange(1, 1, 3, 3); // 1行1列目から3行3列分
```

### getValuesとsetValuesについては次回に続く

* * *
次回更新は講座第7回後の予定です。
引き続きよろしくお願いします！

### 参考書籍
https://www.amazon.co.jp/dp/4798064742