1

I have a small problem with a function that calls itself from within itself. The following function pretty much works, as can be seen here ...

http://jsfiddle.net/justinayles/frPZ8/2/

but if you click a square and after that click the back link and go back and forth a few times, eventually it will slow down and ultimately crash with a 'too much recursion error'. I cant really see any other way to achieve what I am trying to do here ? I kind of understand what the problem is, but was wondering if there was another way to do this, maybe rename the function? im trying to avoid duplication too much code. any help appreciated, thanks.

var questionArray = [];         
var cardArray = [];

// extend array for IE !!
if (!Array.prototype.filter) {
    Array.prototype.filter = function(fun /*, thisp*/) {
        var len = this.length >>> 0;
        if (typeof fun != "function")
            throw new TypeError();

        var res = [];
        var thisp = arguments[1];
        for (var i = 0; i < len; i++) {
            if (i in this) {
                var val = this[i]; // in case fun mutates this
                if (fun.call(thisp, val, i, this))
                    res.push(val);
            }
        }
        return res;
    };
}

function setupPage(whichpage, questionArray) {

    var html = "",
        backlink = "",
        activestep = "",
        undertext = "",
        qArray = questionArray;

    switch(whichpage) {
        case '1':

            var pg1 = questionArray.filter(function (el) {
                return el.page == "step1";
            });

            $.each(pg1, function(key,val) {
                html += '<a class="quest ' + val.star + '" href="' + val.path + '" target="' + val.target + '">' + val.title + '</a>';
            }); 

            backlink = "0"; 
            activestep = "1";
            undertext = "";

            break;              
        case '2a':

            var pg2a = questionArray.filter(function (el) {
                return el.page == "step2a";
            });

            $.each(pg2a, function(key,val) {
                html += '<a class="quest ' + val.star + '" href="' + val.path + '" target="' + val.target + '">' + val.title + '</a>';
            }); 

            backlink = "1";
            activestep = "2";
            undertext = "";

            break;
        case '2b':

            var pg2b = questionArray.filter(function (el) {
                return el.page == "step2b";
            }); 

            $.each(pg2b, function(key,val) {
                html += '<a class="quest ' + val.star + '" href="' + val.path + '" target="' + val.target + '">' + val.title + '</a>';
            }); 

            backlink = "1";
            activestep = "2";
            undertext = "";

            break;
        case '3a':

            var pg3a = cardArray.filter(function (el) {
                return el.page == "3a";
            });

            $.each(pg3a, function(key,val) {
                html += '<div class="cardblock"><a class="wrapcard" href="' + val.path + '" target="' + val.target + '"><img border="0" alt="' + val.title + '" src="http://dummyimage.com/178x112/000/00ffd5.png"  alt="placeholder image" /></a>';
                html += '<a class="cardtitle" href="' + val.path + '" target="' + val.target + '">' + val.title + '</a></div>';
            }); 

            backlink = "2a";
            activestep = "3";
            undertext = "Choose a programme";

            break;
        case '3b':

            var pg3b = cardArray.filter(function (el) {
                return el.page == "3b";
            }); 

            $.each(pg3b, function(key,val) {
                html += '<div class="cardblock"><a class="wrapcard" href="' + val.path + '" target="' + val.target + '"><img border="0" alt="' + val.title + '" src="http://dummyimage.com/178x112/000/00ffd5.png" /></a>';
                html += '<a class="cardtitle" href="' + val.path + '" target="' + val.target + '">' + val.title + '</a></div>';
            }); 

            backlink = "2b";
            activestep = "3";
            undertext = "Choose a programme";

            break;                  
    }

    // make the dom changes..
    if ( backlink !== "0" ) {
        html += '<a id="backlink" href="' + backlink + '">&lt;&lt; back a step</a>';
    }

    $('.wrapdots span').removeClass('active');
    $('.wrapdots span.step'+activestep).addClass('active');

    $('p.underdots').html(undertext);

    $('#wrapper').fadeOut('fast', function() {
        $(this).html(html).fadeIn('fast');
    });

    $('#wrapper').on('click', '#backlink', function(e) {

        e = e || window.event;
        e.target = e.target || e.srcElement;

        var goto = e.target.href;
        goto = goto.split('/');
        goto = goto.pop();

        switch(goto) {
            case '1':
                e.preventDefault(); 
                setupPage('1', qArray);
                break;
            case '2a':
                e.preventDefault(); 
                setupPage('2a', qArray);
                break;
            case '2b':
                e.preventDefault(); 
                setupPage('2b', qArray);                        
                break;
            case '3a':
                e.preventDefault(); 
                setupPage('3a', qArray);
                break;
            case '3b':
                e.preventDefault(); 
                setupPage('3b', qArray);                        
                break;                      
        }

    });

    $('#wrapper').on('click', '.quest', function(e) {

        e = e || window.event;
        e.target = e.target || e.srcElement;

        var goto = e.target.href;
        goto = goto.split('/');
        goto = goto.pop();

        switch(goto) {
            case '1':
                e.preventDefault(); 
                setupPage('1', qArray);
                break;
            case '2a':
                e.preventDefault(); 
                setupPage('2a', qArray);
                break;
            case '2b':
                e.preventDefault(); 
                setupPage('2b', qArray);                        
                break;
            case '3a':
                e.preventDefault(); 
                setupPage('3a', qArray);
                break;
            case '3b':
                e.preventDefault(); 
                setupPage('3b', qArray);                        
                break;  
            default:
                e.preventDefault(); 
                break;
        }

    });

}

// doc ready...
$(function() {

    // do questions
    $('question').each(function() {
        var qobj = { 
            title : $(this).attr('qTitle'),
            star : $(this).attr('class'),
            path : $(this).attr('path'),
            page : $(this).attr('page'),                            
            target : $(this).attr('target')
        }
        questionArray.push(qobj);
    });

    // got the questions, lets now setup page 1 !!
    setupPage('1', questionArray);

    // do cards
    $('card').each(function() {
        var cobj = { 
            title : $(this).attr('cTitle'),
            path : $(this).attr('path'),
            img : $(this).attr('img'),                              
            page : $(this).attr('page'),                            
            target : $(this).attr('target')
        }
        cardArray.push(cobj);                           
    });     

});
4

1 回答 1

1

这不是您想要使用递归的情况。每次单击都会将更多事件绑定到 DOM,但不会释放它们。我建议将您的$('#wrapper').on('click'...代码从您的setupPage函数中提取出来,这样您的点击事件只会绑定一次。

递归函数最适合用于扫描列表树等您不知道它们有多深的情况。仅供参考,Code Academy有关于递归的部分,我觉得很有帮助。

于 2013-07-08T15:17:23.353 回答