MeWrite Docs

RangeError: Maximum call stack size exceeded

JavaScriptで再帰呼び出しが深すぎる場合に発生するエラー

概要

RangeError: Maximum call stack size exceeded は、JavaScriptで再帰呼び出しが深くなりすぎてコールスタックが溢れた場合に発生するエラーです。無限ループの再帰や、意図しない循環参照が主な原因です。

エラーメッセージ

RangeError: Maximum call stack size exceeded
Uncaught RangeError: Maximum call stack size exceeded
    at factorial (script.js:2)
    at factorial (script.js:3)
    at factorial (script.js:3)
    ...

原因

1. 無限再帰

1
2
3
4
5
// 終了条件がない
function infinite() {
  return infinite(); // 無限に呼び出し
}
infinite();

2. 終了条件の間違い

1
2
3
4
5
6
7
8
// 終了条件が間違っている
function factorial(n) {
  if (n = 0) { // == ではなく = (代入)
    return 1;
  }
  return n * factorial(n - 1);
}
factorial(5);

3. 循環参照のJSON変換

1
2
3
const obj = { name: 'John' };
obj.self = obj; // 循環参照
JSON.stringify(obj); // Error

4. イベントリスナーの連鎖

1
2
3
element.addEventListener('click', function() {
  element.click(); // 自分自身をクリック → 無限ループ
});

解決策

1. 正しい終了条件を設定

1
2
3
4
5
6
7
// OK: 正しい終了条件
function factorial(n) {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

2. 末尾再帰最適化(Tail Call Optimization)

1
2
3
4
5
6
7
// 末尾再帰形式に変換
function factorial(n, acc = 1) {
  if (n <= 1) {
    return acc;
  }
  return factorial(n - 1, n * acc);
}

3. ループに変換

1
2
3
4
5
6
7
8
// 再帰をループに変換
function factorial(n) {
  let result = 1;
  for (let i = 2; i <= n; i++) {
    result *= i;
  }
  return result;
}

4. トランポリン関数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
function trampoline(fn) {
  return function(...args) {
    let result = fn(...args);
    while (typeof result === 'function') {
      result = result();
    }
    return result;
  };
}

function factorialTrampoline(n, acc = 1) {
  if (n <= 1) return acc;
  return () => factorialTrampoline(n - 1, n * acc);
}

const factorial = trampoline(factorialTrampoline);
factorial(10000); // スタックオーバーフローなし

5. 循環参照の検出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 循環参照を検出してJSON変換
function safeStringify(obj) {
  const seen = new WeakSet();
  return JSON.stringify(obj, (key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) {
        return '[Circular]';
      }
      seen.add(value);
    }
    return value;
  });
}

6. 非同期処理で分割

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 大量の処理を非同期で分割
async function processLargeArray(arr) {
  const chunkSize = 1000;
  for (let i = 0; i < arr.length; i += chunkSize) {
    const chunk = arr.slice(i, i + chunkSize);
    await processChunk(chunk);
    // イベントループに制御を戻す
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

7. 再帰の深さを制限

1
2
3
4
5
6
7
function deepProcess(data, depth = 0, maxDepth = 100) {
  if (depth > maxDepth) {
    throw new Error('Maximum depth exceeded');
  }
  // 処理...
  return deepProcess(child, depth + 1, maxDepth);
}

関連エラー

関連エラー

JavaScript の他のエラー

最終更新: 2025-12-17