「副作用がある関数」とは、何をしている関数のこと?
解説
正解は「関数の外の状態を変える」です。プログラミングにおける「副作用(side effect)」とは、関数が戻り値を返す以外に、外の世界に何らかの影響を与えることを指します。具体的には、関数の外にある変数を書き換える、画面に出力する(console.log)、ファイルに書き込む、データベースを更新する、APIにリクエストを送るといった操作がすべて副作用です。「戻り値を返す」「引数を受け取る」は関数として当たり前の動作であり、副作用ではありません。「他の関数を呼び出す」も、呼び出した関数自体が副作用を持たなければ問題ありません。副作用の具体例を見てみる以下の関数には副作用があります。let total = 0; function addToTotal(n) { total += n; // 関数の外の変数を変更している return total; } この関数は外部の変数totalを書き換えています。同じ引数で呼んでも呼ぶたびに結果が変わるため、動作が予測しにくくなります。一方、副作用のない関数はこうなります。function add(a, b) { return a + b; } この関数は引数だけを使って計算し、結果を返すだけです。外部の状態には一切触れていません。同じ引数を渡せば何度呼んでも同じ結果が返ります。純粋関数とは何か副作用がなく、同じ入力に対して常に同じ出力を返す関数のことを純粋関数(pure function)と呼びます。純粋関数の条件は2つです。同じ引数を渡せば必ず同じ値を返す(外部状態やDate.now()、Math.random()などに依存しない)副作用がない(関数の外の状態を変えない)先ほどのadd関数は純粋関数ですが、addToTotalは外部変数に依存・変更しているため純粋関数ではありません。console.logも副作用意外に思われがちですが、console.logも副作用です。画面(コンソール)に出力するという「関数の外の世界への影響」があるためです。デバッグ用のconsole.logを残した関数は、厳密には純粋関数ではありません。とはいえ実務では開発中のログ出力まで厳密に排除することは少なく、本番コードから取り除くのが一般的な運用です。副作用は悪いことではない「副作用」という言葉の響きからネガティブな印象を受けますが、副作用がなければアプリケーションは何も役に立ちません。画面を表示するのも、データを保存するのも、APIと通信するのもすべて副作用です。大事なのは副作用を「なくす」のではなく「管理する」ことです。純粋関数で書ける部分は純粋関数にして、副作用が必要な部分は関数の境界をはっきりさせて特定の場所にまとめる。こうすることでコードのテストがしやすくなり、バグの原因も追いやすくなります。ReactのuseEffectが副作用を扱う専用のフックとして分離されているのも、この考え方に基づいています。