Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
636 views
in Technique[技术] by (71.8m points)

javascript - Why is my counter adding more than one each time?

I am creating a test using jQuery, but can't work out why when the correct answer is used my counter variable, count, seems to go up by more than one.

function nextQuestion(){
    $('#submit').show();
    $('#next').hide();
    $('#result').text('');
    $('#value').val('');
    randomNumber = Math.floor((Math.random() * words.length));
    $('#englishWord').text(words[randomNumber][0]);
    $('#submit').click(function(){
        if ($('#value').val() == words[randomNumber][1])
        {
            $('#result').text("You are correct, well done");
            $('#submit').hide();
            $('#next').show();

            $('#next').click(function(){
                count = count + 1;
                $('#score').text(count); 
                nextQuestion();              
            });
        }
        else 
        {
            $('#result').text("That is incorrect, try again");
            count = 0;
            $('#score').text(count);
        }
    });
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

count is increasing by more than one each time there is a click on #next because you are adding multiple anonymous listeners to the click event of the #next element. Each of those functions is independently adding 1 to count. Thus, when #next is clicked, count goes up 1 for each anonymous listener you have added to the click event on the #next element.

Every time there is a click on #submit and $('#value').val() == words[randomNumber][1] you execute:

$('#next').click(function(){
    count = count + 1;
    $('#score').text(count); 
    nextQuestion();              
});

This results in a new anonymous function being added as a listener to the #next element's click event in addition to any ones already listening for that event. Thus, each time there is a click event on #next tehre are multiple functions called which each increases the count by 1. The total amount of the increase for each click on #next depends on how many functions you have listening to that event.

You have the same problem with the click event for the #submit element. This causes count to increase even further by adding even more listeners to the click event of the #next element. The first time #submit is clicked one listener is added. On the the second #submit click two listeners to the #submit click event each add another listener to the #next click event making a total of 3 listeners on that event. Thus, count goes up by 3. This continues to scale as you add more and more listeners to each event.

Have your code add the event listeners only once

The solution to this is to only assign those click events once:

$('#submit').click(function(){
    if ($('#value').val() == words[randomNumber][1])
    {
        $('#result').text("You are correct, well done");
        $('#submit').hide();
        $('#next').show();
    }
    else 
    {
        $('#result').text("That is incorrect, try again");
        count = 0;
        $('#score').text(count);
    }
});

$('#next').click(function(){
    count = count + 1;
    $('#score').text(count); 
    nextQuestion();              
});

function nextQuestion(){
     $('#submit').show();
     $('#next').hide();
     $('#result').text('');
     $('#value').val('');
     randomNumber = Math.floor((Math.random() * words.length));
     $('#englishWord').text(words[randomNumber][0]);
}

Alternately, use a named function and rely on addEventListener() to ignore your attempts to add identical listeners.

An alternate solution is to use a single named function, which is defined in a scope such that it is not redefined each time the code adding it is called. Listeners which are not added using event attributes (e.g. <div onclick="doSomething();">) are added using addEventListener() (jQuery uses this method inside the various methods it provides for adding event listeners). If you try to add the same function, using the same values for the other parameters to addEventListener(), then the additional listeners are discarded. That means that even if you try to add the same function, with the same parameters, more than once, it will only be called once per event. With an anonymous function, the function is separately defined each time that code is run. Thus, while the code is the same, the function that is defined is separate from any prior time the code has run. As a result, multiple copies get added.

However, just because the function has a name does not mean that it is defined in a scope that will result in it not being redefined each time it is added. For instance, in the above code, if the function for the #next listener was defined within the #submit listener, and even if it had a name, it would still be redefined every time the #submit listener was run. To prevent the function from being redefined, the key is how and where the function is defined, not just that it is a named function. However, in order to refer to that function it must have a name, or otherwise be associated with a variable. Thus, you will generally find that there is an assumption made when someone says a "named function" that it is defined in a way that it is not, normally, redefined.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...