LWCのJS内でclassを用意できたので、ループ内で要素の関数が呼び出せるようになった

# はじめに
以前書いたときはJavaScriptのclassの仕組みをあんまり理解できていなかったため、とんちんかんなアプローチをしていました。  
[LWCのJS内でクラス(っぽいもの)を用意したい](https://qiita.com/kft12/items/b8dabe0a53a787edcb67)

今回ある程度学が身についたので「あれ、できるんじゃね？」と試したところあっさりできたので、ご報告も兼ねて完全版を残しておこうと思います。

# やりたかったこと
画面に表示するデータを、同じデータ構造で複数種類保つ必要があったため、クラスに定義して保存するようにしたかった。

# できたこと
## コード
画面用のclassの外で利用したいclassを定義する。  

```javascript:testComponent.js
import { LightningElement } from 'lwc';

export default class TestComponent extends LightningElement {

	personList = [];

	connectedCallback() {
		this.personList.push(new person('テスト　A'));
		this.personList.push(new person('テスト　B'));
		this.personList.push(new person('テスト　C'));
	}
}

class person {
	/**
	 * 名前
	 */
	name;
	/**
	 * 年齢
	 */
	age;
	/**
	 * 身長
	 */
	height;
	/**
	 * 体重
	 */
	weight;

	constructor(name) {
		this.name = name;
		this.age = this.getRandomInt(100);
		this.height = 120 + this.getRandomInt(80);
		this.weight = 30 + this.getRandomInt(100);
	}

	/**
	 * 自己紹介文
	 */
	get selfIntroduction() {
		return `私の名前は${this.name}。\r\n`
			+ `年齢は${this.age}歳だよ。`;
	}

	/**
	 * 乱数を生成する
	 */
	getRandomInt(max) {
		return Math.floor(Math.random() * max);
	}
}
```

```html:testComponent.html
<template>
	<lightning-card icon-name="custom:custom27" title="テスト">
		<div class="slds-var-p-around_medium">

			<template for:each={personList} for:item="person">
				<div key={person.name} class="slds-box slds-var-p-around_small slds-var-m-bottom_small">
					<p>氏名：{person.name}</p>
					<p>年齢：{person.age}歳</p>
					<p>身長：{person.height}cm</p>
					<p>体重：{person.weight}kg</p>
					<div class="slds-box slds-theme_shade">{person.selfIntroduction}</div>
				</div>
			</template>

		</div>
	</lightning-card>
</template>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603116/028c219b-bba3-cbab-f6ee-90af5f89cc01.png)


## 良い点
### 見るべきところを纏められる
他の言語でclassを作ったときと概ね同じ。

### javadocがきちんと効く
以前書いたものだと、コードの記法次第でjavadocが効かないことがあったが、今回のものは完璧！  
javadocがばっちり効きます。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603116/fa8503ae-47f7-5808-42c9-a13ffabf89d4.png)

### 要素ごとのgetterが定義できる → ループ内でそれぞれ動作させられる！
先程のコードサンプルにあった`get selfIntroduction()`をループ内で呼び出してる部分ですが、実は（個人的に）ちょっと画期的なことで・・。  
LWCのループ内部で、要素ごとに関数を適用するのって一筋縄ではできないんですよね。  

そんな悩みもclassを作ることで解決します。やったね。

### apexから渡された値を、かなり手軽にclassに変換できるっぽい
```javascript
const personObject = {
    name: 'テストA'
    ,age: 19
    ,height: 170
    ,weight: 60
    ,unnecessaryProperty: 'abc'
};
const personClass = Object.assign(new person(), personObject));
```

これだけでclassに変換できました。  
余計なプロパティ`unnecessaryProperty` はエラーなどが出たりはせず、保持したままとなっていました。  


## 悪い点
### 未定義プロパティに値を設定できる
誤字や作ったつもりで、未定義のプロパティを参照したとき、なんの問題もなく処理が進んでしまいました。  

classは`use strict`が適用されているはずなんだけど・・なんでだ・・？  
[厳格モード - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Strict_mode)

誤字に気をつけるしかない！というのがちょっと気持ち悪いところではあります。

### privateが使えない
これはLWC側の規約ですが・・。  
privateメソッドやプロパティが使えないようです。  

実際に定義してデプロイすると、下記のエラーが発生します。  
`LWC1535: Unexpected plugin compilation error: Plugin - lwc, Hook - transform, Cause - SyntaxError: LWC1007: /home/sfdc/tools/lwc/248.10.2-5.0.8/testComponent.js: Class private methods are not enabled. Please add '@babel/plugin-transform-private-methods' to your configuration.`

まあ使いたいシーンがあるかと言われると微妙なので、そこまで支障ないとは思いますが・・。  
ちょっと残念。

## 以前と比べて良くなったところ
そもそも、無理やり作ったclassっぽいものではなく、きちんと仕様に則ってclassを作っているというだけでかなりこう、気持ちが違います。

あとは、関数を用意したい場合に別途getterの定義をしなくて良くなったのが大きいですね。  
使い勝手の向上って感じだ。