2

ここで興味深い問題があります。一部のコードを最適化していますが、jQuery ループではなく JavaScript ループを使用するとスコープの問題が発生します。

たとえば、javascript ループを使用して、値が「1950」、「1960」、「1970」の 3 つの「10 年」反復がある場合、常に「1970」(ループの最後の反復) を取得します。 decimal.name の "alert" ですが、jQuery.each を使用して、作成された各要素の期待値を取得します。

質問: - これが通常の JavaScript ループではなく jQuery.each で機能するのはなぜですか? - 通常の JavaScript for ループでこれを機能させるにはどうすればよいですか?

$.ajax({
    async: true,
    type: 'post',
    url: 'ajax/products.php',
    data: {
        'action': 'get_filter_decades',
        'data': {
            "search_term": ple.find('input[name="search_term"]').val(),
            "first_letter": $.bbq.getState('first_letter'),
            "category_id": categoryId.val(),
            "original_release_year_range": ple.find('input[name="original_release_year_range"]').val()
        }
    },
    success: function (jsonResponse) {
        if (jsonObj = handleJsonResponse(jsonResponse)) {
            var filterDecadesResultList = filterDecades.find('ul.decade_result_list');
            filterDecadesResultList.hide();
            filterDecadesResultList.empty();

            var originalReleaseYearRange =     $(ple.find('input[name="original_release_year_range"]'));

            // jquery loop
            //$( jsonObj.data.decades ).each( function( i, decade ) {

            // javascript loop (faster!)
            var decadesLength = jsonObj.data.decades.length;
            var listElement;
            var linkElement;
            var decade;

            for (var i = 0; i < decadesLength; i++) {
                decade = jsonObj.data.decades[i];
                listElement = $('<li />');
                linkElement = $('<a />');
                linkElement.text(decade.name);

                if (decade.product_count > 0) {
                    linkElement.append(' (' + decade.product_count + ')');
                    if (decade.selected) {
                        linkElement.addClass('selected');
                    }
                    linkElement.on("click", function () {
                        alert(decade.name);

                        if (!linkElement.hasClass('selected')) {
                            originalReleaseYearRange.val(decade.name);
                            $.bbq.pushState({
                                'original_release_year_range': decade.name
                            });
                            productListPaginate(ple);
                        } else {
                            originalReleaseYearRange.val('');
                            $.bbq.removeState('original_release_year_range');
                            productListPaginate(ple);
                        }
                    });
                }

                listElement.append(linkElement);
                filterDecades.find('ul.decade_result_list').append(listElement);
                // jquery loop
                //});

                // javascript loop
            }

            filterDecadesResultList.show();
        }
    }
});
4

2 に答える 2

4

jQuery.eachは関数であり、Javascript 関数は自動的にスコープされます。つまり、関数がなくなると、関数内のすべての変数もスコープされます。ただし、純粋な Javascript for ループはフロー制御であるためスコープがありません。含まれているユニットのように見えますが、原則として、他のキーワードやステートメントと同じです。

for ループを同様のスコープにするためにできることはjQuery.each、無名関数のようなものに入れる以外にありません。

(function(){
    for (i=0; i<10; i++) {
        // do something
    }
})();

しかし、これは for ループの動作を実際には変更しません。名前空間をカプセル化するだけなので、無名関数 (および内部の for ループ) が実行された後は何も存続しません。

于 2012-07-05T21:41:23.797 に答える
3

次のサンプルを検討してください: http://jsfiddle.net/9vZUg/1/

var years = [2010, 2011, 2012];
for (var i=0; i<years.length; i++) {
    var year = years[i];
    var input = document.createElement("input");
    input.type = "button";
    input.value = year;
    input.onclick = function(){
        alert(year); // at this point year will be always be 2012
    }
    document.body.appendChild(input);
}​

これは、ある時点で関数を作成し、後で使用するために発生します。現時点では、前回のイテレーションと同じように、年は常に 2012 年と呼んでいます。どうすれば修正できますか?クロージャーを作成します。

var years = [2010, 2011, 2012];
for (var i=0; i<years.length; i++) {
    (function(){
        var year = years[i];
        var input = document.createElement("input");
        input.type = "button";
        input.value = year;    
        // now year is stored here and would be unique for each handler
        input.onclick = function(){
            alert(year);
        }
        document.body.appendChild(input);
    })();
}​
于 2012-07-05T21:47:14.707 に答える