Frage

Auf der folgenden Seite werden fünf Schaltflächen angezeigt. Klicken Sie auf die gesamte Schaltfläche "5". Ich möchte, wenn ich auf die erste Schaltfläche klicke, ich bekomme Alarm '1', die zweite Schaltfläche '2' ... usw.

<!doctype html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
    </head>
    <body>
        <div id="nums"></div>
        <script type="text/javascript">
            var nums = [1,2,3,4,5];
            for(var i in nums){
                var num = nums[i];
                var btn=$('<button></button>').text(num).click(function(){alert(num);});
                $('#nums').append(btn);
            }
        </script>
    </body>
</html>
War es hilfreich?

Lösung

Die Event -Handler -Funktionen, die Sie in der Schleife erstellen, haben eine Dauerhafte Referenz zu den Variablen im Bereich, in dem sie erstellt werden, nicht a Kopieren dieser Variablen zum Zeitpunkt der Erstellung der Funktion. So funktionieren Schließungen (mehr: Schließungen sind nicht kompliziert). Alle Ihre Handlerfunktionen beziehen sich also auf dasselbe num Variable, und sie beziehen sich darauf, wann die click Ereignis tritt auf. Da ist es zu diesem Zeitpunkt 5 (Der letzte Wert, den es jemals zugewiesen hat) 5.

Wenn Sie möchten, dass sich der Event -Handler bezieht num Als der Handler erstellt wurde, muss der Hundeführer sich nicht ändern lassen, was sich nicht ändert. Die übliche Möglichkeit besteht darin, eine Funktion zu haben, die Ihre Handlerfunktion aufbaut und die Handlerfunktion über ein Argument für diese Builder -Funktion schließt:

var nums = [1,2,3,4,5];
for(var i in nums){
    var num = nums[i];
    var btn=$('<button></button>').text(num).click(buildHandler(num));
    $('#nums').append(btn);
}

function buildHandler(val) {
    return function(){alert(val);};
}

Wie Sie sehen können, wir Anruf buildHandler Beim Haken des click Ereignis und geben seinen Rückgabewert in die click. buildHandler erstellt und gibt eine Funktion zurück, die sich schließt val, das Argument, das wir an ihn übergeben. Seit val ist ein Kopieren von der Zahl, die wir wachsamen möchten, und nichts ändert sich jemals val, die Funktionen wie gewünscht.


Off-Topic 1: Sie erstellen viele globale Variablen in diesem Code. Der globale Namespace ist bereits sehr überfüllt. Ich empfehle, mehr Globale zu erstellen, wenn Sie ihn vermeiden können. Ich würde diesen Code in eine Funktion einwickeln, damit die Varizen alle lokal zu dieser Funktion sind:

<script>
    (function() {
        var nums = [1,2,3,4,5];
        for(var i in nums){
            var num = nums[i];
            var btn=$('<button></button>').text(num).click(buildHandler(num));
            $('#nums').append(btn);
        }

        function buildHandler(val) {
            return function(){alert(val);};
        }
    })();
</script>

Es macht dasselbe (wir definieren die Funktion und nennen sie dann sofort), ohne global zu erstellen i, num, nums, und btn Variablen.


Off-Topic 2: Du hast benutzt for..in Mit einem Array ohne Schecks, um sicherzustellen, dass Sie nur mit Array -Indizes zu tun haben. for..in tut nicht Schleifen durch Array -Indizes; Es schaltet sich durch Objekteigenschaften. Schreiben for..in Loops, als würden sie durch Array -Indizes geschleudert, werden Sie irgendwann beißen. Verwenden Sie einfach einen Normalen for Schleifen oder die erforderlichen Schecks durchführen oder JQuery's verwenden each Funktion. Mehr: Mythen und Realitäten von for..in

Andere Tipps

JavaScript hat nur Funktionsumfang. In Ihrem Beispiel gibt es also nur einen num, was immer wieder geändert wird, und bis zum Klickereignis entspricht es fünf. Um dies zu umgehen, müssen Sie das Recht erstellen Schließung Mit einem neuen Funktionsbereich wie folgt:

var nums = [1,2,3,4,5];
var createClick = function (num) { return function() { alert(num); }; };
for(var i in nums){
    var num = nums[i];
    var btn=$('<button></button>').text(num).click(createClick(num));
    $('#nums').append(btn);
}  

Ändern Sie diese Zeile:

var btn=$('<button></button>').text(num).click(function(){alert($(this).text()});

Alle der click Handler, die Sie erstellen, beziehen sich auf dieselbe globale Variable num, was 5 sein wird, nachdem die Schleife ausgeführt wurde, und immer noch fünf an dem Punkt, an dem Sie tatsächlich klicken, um den Handler auszulösen und die Warnung anzuzeigen.

Zwei Möglichkeiten, sich umzugehen, die wie folgt sind:

(1) Wenn Sie die Nummer bereits als Text der Schaltfläche festlegen, verwenden Sie diese innerhalb des Handlers wie folgt:

// jQuery will set 'this' for you when it calls your click handler
[...].click(function(){ alert($(this).text()); });

(2) eine Schließung erzeugen, damit die individuellen Werte von num werden für jeden Handler beibehalten:

[...].click((function(closureNum){
                return function(){ alert(closureNum); }
             })(num));

Bearbeiten: Ich habe gerade die anderen Antworten gesehen. Für eine bessere Variation meiner zweiten Option würde ich empfehlen, das zu tun, was TJ und FishBasketgordo getan haben, und eine separate Handler -Baufunktion haben, anstatt dies inline zu machen, wie ich es getan habe. Beide sollte funktionieren, aber der separate Händlerbauer sollte effizienter sein (und wohl einfacher zu lesen).

Versuche dies

<script type="text/javascript">
            var nums = [1,2,3,4,5];
            for(var i in nums){
                var num = nums[i];
                var btn=$('<button></button>').text(num).click(function(){alert(nums[i]);});
                $('#nums').append(btn);
            }
        </script>

Das ist einfacher:

var nums = [1,2,3,4,5];
$.each(nums, function(index, value){
    var btn=$('<button></button>').text(value).click(function(){alert(value);});
    $('#nums').append(btn);
});

Warum verwenden Sie $ .each (), da Sie bereits JQuery auf Ihrer Seite haben?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top