JavaScript入門 副作用のない関数を書いてみよう

関数を書く時に副作用がない関数を書くと汎用性があがるし、予期せぬ動作(バグ)も少なくなります。

これを実践するために、「同じ入力なら同じ結果を返す」ということを意識して関数を書いてみます。

副作用があるケース

以下のコードをみてください。

const calcAge = (birthYear) => {
	const currentYear = new Date().getFullYear();
  return currentYear - birthYear;
}

const age = calcAge(1987);
console.log(age) // 33

calc は引数で与えられた年と現在の年を基に年齢を返します。

この関数は同じ入力に対して同じ結果を返すでしょうか

答えはノーです。2020年の時点でこの関数を実行すると33ですが、2021年の時点で実行すると34が返ります。

原因は関数の中で new Date() を実行しているためです。この処理をみたら、「これは副作用があるな」ということを頭の片隅に入れておくと良いと思います。

この関数を使う人は、引数で渡した値の他に、この関数がいつ実行されるのかが結果に影響することを常に意識しなくてはいけません。これを忘れると意図しない結果になります。

副作用がないケース

それではどうしたら副作用がない関数をかけるのでしょうか。

答えは簡単で、calcAge 内から new Date() を無くします。

const calcAge = (baseYear, birthYear) => {
  return baseYear - birthYear;
}

const age = calcAge(new Date().getFullYear(), 1987);
console.log(age) // 33

calcAge はとてもシンプルになりました。これで「同じ入力なら同じ結果を返す」となりました。

しかし、ここで「結局 new Date().getFullYear() は使っているじゃん」と思うかもしれません。

システムを組む時に、副作用を完全になくすことはほぼ不可能です。

なくすのではなく、副作用があるものとないものをできるだけ分けることが大切です。

そして、副作用がない処理から副作用がある処理を呼び出さないようにします

もし、副作用がない関数の中で、副作用がある関数を読んでしまったら、もはや副作用がない関数ではなくなるからです。

  • できるだけ副作用がない処理と、副作用がある処理を分ける
  • 副作用がない処理から、副作用がある処理を呼ばないようにする
  • 副作用がある処理から、副作用がない処理を呼ぶのはOKとする

これらを頭にいれてプログラムを書くことで、汎用性があり、バグが生まれにくいコードを書くことができるはずです。

ぜひトライして、ステップアップしてみてください。