知ってるとかっこよくなれるJS小技集2019

## はじめに

コードレビューでさらっと 
「こんな書き方もできますよ」って言ってくれる先輩ってかっこいいですよね。
いつかそんな先輩になれるように、メモ化しておこうという試みです。クリスマスのお供にどうぞ。

## 記法

#### 変数名が同じなら省略できる

```javascript
const params = {
   id: id
   name: name
}
```
```javascript
const params = {
   id,
   name
}
```

#### {}で分割代入

似てるものでこういう省略系もあります。分割代入と言うらしいです。

```javascript
const id = response.id;
```
```javascript
const {id} = response;
```

複数もOK

```javascript
const {id, name} = response;
```

実務でよくみる使い方だと、Reactでpropsから値取り出すときとかでしょうか。

```javascript
const {width, height} = props;
return (
  <div style={{ width, height }} />
)
```

#### スプレッド演算子...で展開できる


```javascript
const hoge = {
    id: fuga.id,
    name: fuga.name,
    type: fuga.type
}
```

```javascript
const hoge = {
    ...fuga
}
```

展開してさらに追加してもOK

```javascript
const hoge = {
    ...fuga,
    date: Date.now()
}
```

実例だと、ReduxでStateを一部更新するときなんかに使えますね

```javascript
  [HogeAction.SOMETHING]: (state: IHogeState, action: any): IHogeState => ({
    ...state,
    fuga: action.payload
  })
```

オブジェクトをコピーするためにも使えますが、Object.assign同様ディープコピーではないので注意です。

```javascript
const original = {
   id: 1,
   obj: {
      name: "shwan"
   }
};

const copy = { ...original };
console.log(copy.obj.name); // "shwan"
original.obj.name = "changed";
console.log(copy.obj.name); // "changed"

```

オブジェクトのディープコピー技だとこんなのもありますが、undefindを扱えない罠があったりするので、できるだけ避ける人生を歩みたいですね。

```javascript
const copy = JSON.parse(JSON.stringify(original));
```

スプレッド演算子に話をもどすと、引数でも展開できたりします。使う場面はあまりなさそうですが。

```javascript
doSomething(fuga.id, fuga.name, fuga.type);
```

```javascript
doSomething(...fuga);
```

## 条件分岐

#### 論理演算子 || で条件分岐

```javascript
let name;
if (response.name) {
    name = response.name
} else {
    name = 'Guest';
}
```
```javascript
const name = response.name || 'Guest';
```

nullかもしれない配列を空配列にするときによく使います

```javascript
response.names.forEach() // response.namesがnullやundefindだとエラー
```

```javascript
const arr = response.names || [];
arr.forEach()
```

#### 論理演算子 && で条件分岐

```javascript
if (isGuest) {
    doSomething();
}
```
```javascript
isGuest && doSomething();
```

この記法、 `if( A && B )` `if( A || B )` なときと違う動きをしてるようにも見えますが
 `&&` は **左が偽なら左の値**を、**真なら右の値**を返す
 `||` は **左が真なら左の値**を、**偽なら右の値**を返す
という共通の仕組みです。

```javascript
const name = response.name || 'Guest';
```
 の例では`response.name`が`'shwan'`などの文字列であれば左が真とみなせるので、左の値が返り、`''`や`null`であれば、偽なので`Guest`が返ります。

## キャスト
#### 論理否定演算子 ! でのbooleanキャスト

```javascript
const isSelected = this.state.type ? true : false;
```

```javascript
const isSelected = !!this.state.type;
```

この記法も!を2つつなげると `if(!isSelected)` なときと違う用法にみえますが、
どちらも同じ論理否定演算子で、**値を真偽値とみなしたうえで真偽を反転する** という動きをしています。

#### + でのnumberキャスト
```javascript
const id = '1'
console.log(+id); // 1
```

```javascript
console.log(new Date()); // Wed Nov 27 2019 21:00:38 GMT+0900 (日本標準時)
console.log(+new Date()); // 1574856056863
```

キャストできなければ`NaN` になるので使い所は見きわめましょう。
ちなみにnew DateはDate.now()を使えばキャストせずとも数値で出せます。

```javascript

console.log(Date.now()); // 1574856056863
```

## letしない

#### 三項演算子でletの回避


```javascript
let type = 'a';
if (isB) {
    type = 'b';
}
```
```javascript
const type = isB ? 'b' :'a';
```

#### 即時関数でletの回避
複雑な分岐なら即時関数を使って回避することもできますね。このあたりは可読性とトレードオフでしょうか。 

```javascript
const type = ((flag) => {
  if (flag) {
    return 'a';
  } else {
    return fukuzatuNaSomething();
  }
})(isB);
```

## その他Tips

#### 関数の引数に初期値を設定する

初期値をつけておけば条件分岐を減らせます

```javascript
const doSomething = (a, b = 1) => a * b;
doSomething(1); // 1
doSomething(1, 2); // 2
```

#### someで繰り返し処理を途中で抜ける

```javascript
arr.forEach((obj) => {
  doSomething
  if(shouldBreak){
    //break; ←できない
  }
})
```

```javascript
arr.some((obj) => {
  doSomething
  if (shouldBreak) {
    return true;
  }
  return false;
})
```

#### someで配列の中を調べる

includes代わりに使えます

```javascript
const arr = ['a', 'b', 'c'];
arr.includes('b') // true
```
```javascript
const arr = [{
  name: 'shwan'
},{
  name: 'taro'
}];
arr.some((person) => person.name === 'shwan') // true
```

#### 対象が配列なのか調べる

```javascript
Array.isArray(target)
```

#### 対象がオブジェクトなのか調べる

```javascript
Object.prototype.toString.call(target).slice(8, -1).toLowerCase() === 'object';
```

ここでいうオブジェクトは `{id: 1, name:'a'} `こういうのです。配列のようにスッキリは書けないので一工夫必要になります。


そろそろネタがなくなって極小ネタになってきたので、また来年に向けて溜め直してきます！