Obiekty DOM dynamicznie

Napotkałem w JavaScript mały “błąd”. Oczywiście owy wynikał z mojej niewiedzy, ale mógłby przysporzyć wiele kłopotów. Kiedy tworzymy dynamicznie listę pewnych linków i zamiast atrybutu ‘href’ przypisujemy odpowiednio ‘onclick’, wtedy właśnie napotykamy tę omyłkę. Przedstawiam krótkie rozwiązanie.

Jak było

for (var i = 0; i < photos.length; i++) {
    var name = photos[i];

    var anch = document.createElement('a');
    anch.href = "#";
    anch.onclick = function() {
        selectPhoto(name); //tutaj zaczyna sie problem
    };

    div.appendChild(anch);
}

Gdy już pętla przejdzie przez wszystkie elementy (tu: zdjęcia) tablicy, na końcu okazuje się, że każdy dodany link ma identyczną funkcję onclick. Zmienna name niby się zmieniała za każdym przebiegiem pętli, ale na końcu wszystkie linki odnosiły się do ostatniej wartości name. Innymi słowy – kliknięcie obojętnie którego z wygenerowanych linków odnosiło ten sam efekt – jak kliknięcie ostatniego z nich.

Dlaczego tak?

JavaScript nie tworzy tutaj nowego obiektu funkcji (przypominam – funkcje w JS są obiektami), ale zapisuje jego lokalną wersję jakby globalnie. To znaczy, że dla każdego przebiegu pętli jest przypisywany dokładnie ten sam obiekt funkcyjny. Parametr, z którego on korzysta (name), to już tylko dodatek, mała wzmianka w tym obiekcie funkcyjnym.

Rozwiązanie

Aby umożliwić prawidłowe działanie tego skryptu, należy w każdym przebiegu for wykreować nowy obiekt funkcyjny. Odpowiedni rezultat dało coś takiego:

    function anchOnClick(n) {
        return function() {
            selectPhoto(n);
        };
    };

    anch.onclick = anchOnClick(name);

Jak widać, nic nadzwyczajnego. return function(){ … } zwraca nowy obiekt funkcji. To wszystko.

Tagi: , , , , , ,

Zostaw odpowiedź