質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

3回答

2806閲覧

JavaScriptエラー「too much recursion」の回避法

skipping

総合スコア14

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

1クリップ

投稿2018/09/21 02:17

編集2022/01/12 10:55

###質問
親子階層のスライダーを作りにあたり、「too much recursion」のエラーが出てしまいました。

解決方法についてご指南頂けませんでしょうか。

###経緯
HTMLで2世代以上の入れ子が作れず、JavaScriptで親子関係とスライダーを実装してします。

仕組みは、先祖番号を連結した疑似的な入れ子によって親子関係とし、親の「open」クリック後にその子がスライダー表示される。というものです。

Sample:https://jsfiddle.net/nd6jser0/

ところがこの親子の数が増えると、上記のSampleのvar parent_nums = getParentNums(parent);の部分で「too much recursion」のエラーとなってしまいます。

解決方法がわからず、質問させて頂きました。

###コード
こちらが上記のSampleコードです。

空のancestor=""に先祖番号が連結され、子がいる場合にのみ「open」ボタンが表示される仕組みです。

html

1<div class="alllists"> 2 <ul> 3 4 <li> 5 <div id="post-7" class="list" parent="0" ancestor="">X家 6 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 7 </div> 8 <ul class="childrens"> 9 <li> 10 <div id="post-39" class="list" parent="7" ancestor="">A 11 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 12 </div> 13 </li> 14 </ul> 15 </li> 16 17 <li> 18 <div id="post-157" class="list" parent="0" ancestor="">Y家 19 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 20 </div> 21 <ul class="childrens"> 22 <li> 23 <div id="post-200" class="list" parent="157" ancestor="">B 24 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 25 </div> 26 </li> 27 <li> 28 <div id="post-354" class="list" parent="157" ancestor="">C 29 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 30 </div> 31 </li> 32 <li> 33 <div id="post-365" class="list" parent="354" ancestor="">D(Cの子) 34 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 35 </div> 36 </li> 37 <li> 38 <div id="post-503" class="list" parent="365" ancestor="">E(Dの子) 39 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 40 </div> 41 </li> 42 <li> 43 <div id="post-514" class="list" parent="503" ancestor="">F(Eの子) 44 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 45 </div> 46 </li> 47 </ul> 48 </li> 49 50 <li> 51 <div id="post-705" class="list" parent="0" ancestor="">Z家 52 <span class="my_post_num"></span><span class="my_ancestor_num"></span> 53 </div> 54 </li> 55 56 </ul> 57</div>

エラーの箇所はJavaScriptの8行目です。

javascript

1//➀先祖番号の連結 2function getParentNums(list) { 3 var parent_num = list.attr('parent'); 4 if (parent_num == "0") { 5 return ["0"]; 6 } 7 var parent = $("#post-" + parent_num); 8 var parent_nums = getParentNums(parent); 9 parent_nums.push(parent_num); 10 return parent_nums; 11} 12$('.list').each(function() { 13 var my_post_num = $(this).attr('id').split('-')[1]; 14 var list = $(this); 15 var parents = getParentNums(list); 16 var my_ancestor_num = parents.join('-'); 17 list.attr('ancestor',my_ancestor_num); 18 //確認のための表示 19 $(this).find('.my_post_num').text(my_post_num); 20 $(this).find('.my_ancestor_num').text(my_ancestor_num); 21}); 22 23 24//➁子がいたらボタンを表示 25var parents = []; 26$(".list").each(function() { 27 var parent_num = $(this).attr('parent'); 28 parents.push( parent_num ); 29}); 30$(".list").each(function() { 31 var my_post_num = $(this).attr('id').split('-')[1]; 32 if (parents.indexOf(my_post_num) >= 0){ 33 $(this).append('<button class="opento">open</button>'); 34 } 35}); 36 37 38//➂openボタンをクリックしたら 39$('body').on("click",".opento",function(){ 40 41 //ボタン表示を切り替えて 42 $(this).removeClass('opento').addClass('closeto').text('close'); 43 44 //子リストを開く 45 var click_post_num = $(this).closest('.list').attr('id').split('-')[1]; 46 var click_ancestor_num = $(this).closest('.list').attr('ancestor'); 47 var child_ancestor_num = click_ancestor_num+'-'+click_post_num; 48 $(".list").each(function() { 49 var ancestor_num = $(this).attr('ancestor'); 50 if (ancestor_num == child_ancestor_num){ 51 $(this).closest('li').slideDown(); 52 } 53 }); 54 55}); 56 57 58//➃closeボタンをクリックしたら 59$('body').on("click",".closeto",function(){ 60 61 //ボタン表示を切り替えて 62 $(this).removeClass('closeto').addClass('opento').text('open'); 63 64 //子リストを閉じる 65 var click_post_num = $(this).closest('.list').attr('id').split('-')[1]; 66 var click_ancestor_num = $(this).closest('.list').attr('ancestor'); 67 var child_ancestor_num = click_ancestor_num+'-'+click_post_num; 68 $(".list").each(function() { 69 var ancestor_num = $(this).attr('ancestor'); 70 if (ancestor_num.match(child_ancestor_num)){ 71 $(this).closest('li').slideUp(); 72 $(this).closest('li').find('.closeto').removeClass('closeto').addClass('opento').text('open'); 73 } 74 }); 75 76}); 77

長くなってしまい申し訳ございませんが、どうすれば親子の数が増えてもvar parent_nums = getParentNums(parent);の部分でエラーが出ないようになるかについて、ご意見頂ければ幸いです。
どうぞ宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dice142

2018/09/21 02:35

エラーが再現しないのですが、こちらはエラーが出るバージョンのコードではないのでしょうか?
dice142

2018/09/21 02:36

ついでにエラーを読んでどういうことを試してみたのかも記入いただければ助かります。
sousuke

2018/09/21 03:03

エラーが再現しません。上限があるとはいえかなりの回数再帰できるはずですので原因は「親の指定が間違っている」のでは?
skipping

2018/09/22 07:49

失礼致しました。親の指定でした。
think49

2018/09/22 08:44 編集

To: @skipping さん、あなたの環境で https://jsfiddle.net/nd6jser0/ を開き、エラーが再現されることを確認して下さい。確認出来たら、再現手順を質問文に追記して下さい。あと、環境(ブラウザ名とバージョン)は書いた方が良いです。
guest

回答3

0

何らかの原因で親が取れない場合、getParentNums()で無限に再帰します。

投稿2018/09/21 02:52

x_x

総合スコア13749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skipping

2018/09/22 07:49

原因を特定して頂きありがとうございます。
guest

0

再帰関数を使っている以上、増やせばオーバーフローするのは当たり前です。
このまま回避するのであれば、トランポリンすればよいです。

こちらの記事がわかりやすいです。
https://qiita.com/41semicolon/items/985bdd2f551d9392463c

投稿2018/09/21 02:46

macaron_xxx

総合スコア3191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

エラー「too much recursion」

親子階層のスライダーを作りにあたり、「too much recursion」のエラーが出てしまいました。

エラーメッセージは Firefox のもの。
関数を5万回、再帰呼び出しする事で当該エラーメッセージを確認しました(Firefox v57.04)。

JavaScript

1function recursion (i) { 2 return i ? recursion(--i) : i; 3} 4 5recursion(50000); // too much recursion

再現条件

コードから読み取れる再現条件は、次のいずれか一つを満たす事です。

  • <div class="list"> が5万個、入れ子になっている
  • <div id="post-1" parent="1"> のように、id, parent 属性内の数値が同一 -> 同一要素を参照し続ける(無限ループ)
  • <div id="post-undefined"> で同一要素を参照し続ける(無限ループ)
  • <div id="post-1" parent="2"> -> <div id="post-2" parent="1"> で循環参照している(無限ループ)
  • <div parent="-1"> 存在しないparent属性値を指定している
  • 参照される要素内に parent="0" が存在しない

例外判定の甘さが多いので、今あるコードは捨てて、アルゴリズムから見直すべきだと思います。
あと、parent, ancestor 等の独自属性を定義する際には、data-* 属性が良いと思います。

Re: skipping さん

投稿2018/09/22 09:39

編集2018/09/22 09:44
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問