1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptにおける関数型思考の導入:副作用排除・純粋性・合成可能性の設計戦略

Posted at

概要

関数型プログラミングは“考え方”であり、“制約”ではない。
JavaScriptでもその思想を取り入れることで、コードは明確に、状態は安全に、ロジックは再利用可能になる。

本稿では、以下の視点から関数型思考をJavaScriptへ導入する:

  • 副作用(Side Effect)とその管理
  • 純粋関数とテスタビリティ
  • 不変性(Immutability)と構造共有
  • 高階関数と関数合成
  • 実用ライブラリ(Ramda, Lodash/fp等)の活用

1. 副作用(Side Effect)の定義と排除

副作用とは、関数の外部世界に影響を及ぼす操作のこと。

例:DOM操作、ログ出力、API通信、グローバル変数の変更

// ❌ 副作用あり
function saveUser(user) {
  localStorage.setItem('user', JSON.stringify(user));
}

// ✅ 副作用を外に逃がす
function serializeUser(user) {
  return JSON.stringify(user);
}

→ ✅ 副作用は関数外へ押し出し、純粋ロジックと処理を分離


2. 純粋関数とは?

  • ✅ 同じ入力 → 同じ出力
  • ✅ 外部状態に依存しない
  • ✅ 外部状態を変更しない
function add(a, b) {
  return a + b;
}

→ ✅ テストが簡単、再利用しやすく、構成可能


3. 不変性(Immutability)の維持

// ❌ オブジェクトを直接変更
user.name = 'Toto';

// ✅ 新しいオブジェクトを返す
const updatedUser = { ...user, name: 'Toto' };

→ ✅ データ構造を破壊せず、安全に状態管理ができる


4. 高階関数(Higher-Order Functions)

✅ 関数を“受け取る”または“返す”関数

function map(arr, fn) {
  const result = [];
  for (const item of arr) {
    result.push(fn(item));
  }
  return result;
}

map([1, 2, 3], x => x * 2); // [2, 4, 6]
  • ✅ 抽象化と再利用のための中核パターン
  • .map, .filter, .reduce もすべて高階関数

5. 関数合成(Function Composition)

✅ 関数をつなぎ、パイプライン化

const trim = (s) => s.trim();
const toUpper = (s) => s.toUpperCase();

const cleanAndUpper = (s) => toUpper(trim(s));

→ ✅ 小さな関数をつないで大きな機能を構築する


RamdaやLodash/fpの活用例

import { pipe } from 'ramda';

const cleanAndUpper = pipe(
  (s) => s.trim(),
  (s) => s.toUpperCase()
);

→ ✅ データフローを左→右で直感的に記述可能


6. 実用例:ユーザーの年齢フィルタ → 名前抽出 → 大文字変換

const users = [
  { name: 'toto', age: 28 },
  { name: 'momo', age: 18 },
  { name: 'kiki', age: 35 }
];

const result = users
  .filter(u => u.age >= 20)
  .map(u => u.name.toUpperCase());

→ ✅ 副作用なし、純粋関数による安全なデータ変換チェーン


設計判断フロー

① この関数は同じ入力で同じ出力か? → 純粋関数か確認

② 外部状態を変更していないか? → 副作用を外部へ

③ 状態を破壊していないか? → イミュータブルに扱う

④ 処理を関数で分けられるか? → 高階関数で抽象化

⑤ 合成して流れにできるか? → pipe / composeの導入

よくあるミスと対策

❌ 関数内で外部変数を更新

→ ✅ 状態を引数で受け取り、出力で返す構造に


❌ 再利用性のない巨大な関数

→ ✅ 小さな純粋関数に分解し、合成する設計へ


❌ map内で副作用操作(console, fetchなど)

→ ✅ .map() は純粋関数だけに使うことを徹底


結語

関数型思考とは「ロジックを“構造化”し、状態を“制御可能”にする設計戦略」である。

  • 副作用を隔離し
  • 関数を分解し
  • データを変換で流し
  • 構造を組み合わせる

予測可能性、テスタビリティ、再利用性――
そのすべてが“純粋な関数”から生まれる。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?