toNumber 時に副作用を起こさせる。

ある日のニジボックスメンバーの times にて。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6031/5ac80362-c643-ae27-74f1-51abd3a70fdc.png)

で、これを見た時に「おや？」となったんですよね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6031/1282328d-fe29-21a9-fe22-887e4de484e7.png)

まぁ単純に上のif文を消し忘れただけだと思うんですが、このままだとどうあがいても4行目以降の三項演算子まで到達しません。

ただ、ちょろっと変えると4行目以降の三項演算子部分に到達させることができます。

そこで、以下のチャレンジを思いつきました。

# 問題

以下の関数に何かを渡して、 "申込書到達" って出せる applicationProgressValue の引数の値を示しなさい。

```javascript
const applicationProgressValue = (num) => {
  if (num != 0 || num != 1 || num != 2) {
    return "";
  }
  return num == 0
    ? "申込書到達"
    : num == 1
    ? "申込手続中"
    : num == 2
    ? "申込完了"
    : "";
};
```

もしも自分で解いてみたいという方は下の解答を見ないで、ちょっと時間を使って解いてみてください。

ヒント: 厳密等価演算子 (`===`) ではなく、等価演算子 (`==`) にしてます。



# 解答

```javascript
var n = { 
  v: 0, 
  valueOf: function() {
    if (this.v > 2) {
      this.v = 0
    }
    return this.v++
  }
}

applicationProgressValue(n); // 申込書到達
```

`valueOf` を使います。等価演算子の中で Primitive での比較を行うため、暗黙の primitive 変換を行います。その時に `valueOf` 関数の中で `v` を increment させて、副作用を起こさせます。

```javascript
const applicationProgressValue = (num) => {
  if (
    num != 0 || // num: 0
    num != 1 || // num: 1
    num != 2) { // num: 2
    return "";
  }

  return num == 0 // num: 0 if (num > 2) v = 0 になるので。
    ? "申込書到達" // return される。
    : num == 1
    ? "申込手続中"
    : num == 2
    ? "申込完了"
    : "";
};
```

`valueOf` で副作用を及ぼせる、というのはこういう時によく使いますね。まぁ知らなくてもいいっちゃいいんですけど、知っておくと何かといいかと。

# 問題2

もう一つ問題を作りました。

以下の関数に何かを渡して、 "申込書到達" って出せる applicationProgressValue の引数の値を示しなさい。ただし、 <b>if 文の中身の順序が変わることがあります</b>。順序に依存してはいけません。

```javascript
const applicationProgressValue = (num) => {
  if (+num !== 0 || `${num}` !== "1" || (num + "") !== "false") {
    return "";
  }
  return +num === 0
    ? "申込書到達"
    : +num === 1
    ? "申込手続中"
    : +num === 2
    ? "申込完了"
    : "";
};
```

こっちのが若干ハッキーですね。解いてみたい方は解いてみてください。

ヒント: 厳密等価演算子になっていますが、明示的にこちらから型を変換しています。

# 解答2

```javascript
var n = {
  [Symbol.toPrimitive]: function(hint) {
    if (hint === "string") {
      return "1";
    }
    if (hint === "number") {
      return 0;
    }
    return false;
  }
};

applicationProgressValue(n); // 申込書到達
```

今回は primitive に変換するのですが、 valueOf で副作用を及ぼす技は封じられています。その代わり、 primitive への変換をこちらで明示的に行ってから比較しています。

また、 if 文の中身が `+num !== 0 || `${num}` !== "" || (num+"") !== "false"` だったり、 `(num+"") !== "false" || `${num}` !== "" || +num !== 0` だったりと中身の順序が書き換わったとしても動く必要があります。

`Symbol.toPrimitive` は ES2015 から新しく追加された Primitive 関数に変更する時の関数です。これの第一引数（上の例で言う `hint` ）に `string`, `number`, `default` といった文字列が型の変換時にhintとして入ります。

`+num` とやった場合は数値への変換なので `number` になり、 `${num}` とやった場合は文字列への変換なので `string` になります。それ以外の場合、特に足し算は number でも string でも使うので `default` になります。

これを使って Symbol.toPrimitive 関数を作れば良いです。

```javascript
const applicationProgressValue = (num) => {
  if (+num !== 0 ||      // hintは number なので 0
      `${num}` !== "1" || // hintは string なので ""
      (num+"") !== "false") {    // hintは default なので false
    return "";
  }
  return +num === 0 // +num は 0 なので
    ? "申込書到達"  // 申込書到達
    : +num === 1
    ? "申込手続中"
    : +num === 2
    ? "申込完了"
    : "";
};
```

元々は雑談で書いてあったコードをちらっと見たら面白かったので、メンバーに問題として提示してしまったというプログラミングクイズでした。

参考:
https://qiita.com/yosuke_furukawa/items/e59a1766b1aec686b4df