groupBy で学ぶ JavaScript の真偽値

## なにこの記事&なぜ

- ES6 以降の構文で groupBy を書いた。そのときに調べたことを残す。
- [Object.groupBy() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy)
  - ここのサンプルコードをブラウザのコンソールにコピペしたら動かなかった(記事を書いてるときにコピペしたら動きました)のがきっかけ。

## 先に結論だけ教えて

- JavaScript ではデータを持たないことを示す型が ```null``` と ```undefined``` に分かれている
- JavaScript では連想配列に存在しないキーを指定してもエラーにならず、```undefined``` を返す
- ```undefined``` は ```false``` として扱われる値のひとつ(Falsy)
- 比較演算子 == は、比較する値の型が異なる場合、JavaScript内部で暗黙の型変換を行う

## サンプルコード:groupBy

こちらのソースコードをご覧ください。いくつか既存の groupBy 実装を見ながら書いたものです

```javascript
const inventory = [
  { name: "asparagus", type: "vegetables", quantity: 5 },
  { name: "bananas", type: "fruit", quantity: 0 },
  { name: "goat", type: "meat", quantity: 23 },
  { name: "cherries", type: "fruit", quantity: 5 },
  { name: "fish", type: "meat", quantity: 22 },
];

const key = "type";
const res = inventory.reduce((accumulator, current) => {
  const index = current[key];
  accumulator[index] = accumulator[index]
    ? [...accumulator[index], current]
    : [current];

  return accumulator;
}, {});
```

## ここ読みづらくないですか？

```javascript
  accumulator[index] = accumulator[index]
    ? [...accumulator[index], current]
    : [current];
```

- オブジェクトに存在しないキーを指定してもエラーを返さず、```undefined``` を返す。
    - たとえば Python とかは ```KeyError``` を返してきます
- 条件文に ```bool``` ではない値が入っている
    - ただし、```undefined``` は JavaScript の暗黙の型変換によって false として扱われる
    - falsy ではない値は true として扱われる(Truthy)
- 三項演算子か代入のどちらかが、次の行を読むまでわからない

### ちょっと書き換えてみる：暗黙の型変換を避ける

```javascript
const inventory = [
  { name: "asparagus", type: "vegetables", quantity: 5 },
  { name: "bananas", type: "fruit", quantity: 0 },
  { name: "goat", type: "meat", quantity: 23 },
  { name: "cherries", type: "fruit", quantity: 5 },
  { name: "fish", type: "meat", quantity: 22 },
];

const key = "type"
let ret = {};
for (const item of inventory) {
  const index = item[key];
   if (index in ret) {
    ret[index].push(item);
  } else {
    ret[index] = [item];
  }
}

// 以下テストコード
const res = inventory.reduce((accumulator, current) => {
  const index = current[key];
  accumulator[index] = accumulator[index]
    ? [...accumulator[index], current]
    : [current];

  return accumulator;
}, {});

console.log(ret)
const result = JSON.stringify(res) === JSON.stringify(ret)
console.log("JSON.stringify(res) === JSON.stringify(ret):",result)

```

- ```in```演算子を使えば ```bool``` にでき、暗黙の型変換を避けつつ代入と見間違うことはない
- reduce と分割代入はお好みで使ったり使わなかったりしてください

## JavaScript のふしぎな動作

なんで暗黙の型変換を避けたいかと言えば、こういうことがあるからです。

```js
[] ? "T" : "F";
// "T"
[] == true ? "T" : "F";
// "F"
```


## なんでこうなるの？

比較演算子 ```==``` は、比較する値の型が異なる場合、JavaScript内部で暗黙の型変換を行うからです。

```javascript
[] == "" ? "T" : "F"
// "T"
[] == 0 ? "T" : "F"
// "T"
"" == false ? "T" : "F"
// "T"
[] == false ? "T" : "F"
// "T"
```

## 参照

- [等価 (==) - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Equality)
- [Boolean - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Boolean#%E8%AB%96%E7%90%86%E5%80%A4%E3%81%B8%E3%81%AE%E5%9E%8B%E5%BC%B7%E5%88%B6)
- [Falsy (偽値) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN](https://developer.mozilla.org/ja/docs/Glossary/Falsy)