для цикла против forEach в JavaScript — пример из книги

#javascript #jquery #foreach

#javascript #jquery #foreach

Вопрос:

В настоящее время я изучаю JavaScript с помощью книги О’Рейли «Learning Web Application Development». В примере мы создаем веб-сайт с использованием HTML и CSS, который включает в себя 3 вкладки, которые должны быть выбраны и стать «активной» вкладкой. В книгах утверждается, что следующие два способа написания кода табуляции эквивалентны:

1)

 var main = function() {
    "use strict";
    var tabNumber;
    for (tabNumber=1;tabNumber<=3;tabNumber  ) {
        var tabSelector = ".tabs a:nth-child(" tabNumber ") span";
        $(tabSelector).on("click",function() {
           $(".tabs span").removeClass("active");
           $(tabSelector).addClass("active");
           $("main .content").empty();
           return false;
        });
    }  
}
$(document).ready(main);
  

2)

 var main = function() {
    "use strict";
    $(".tabs a span").toArray().forEach(function(element) {

        $(element).on("click", function() {
            console.print("this element: "   element);
            $(".tabs span").removeClass("active");
            $(element).addClass("active");
            $("main .content").empty();
            return false;
        });
    });
}
$(document).ready(main);
  

Однако они не выдают одинаковый результат. Версия, использующая forEach, работает корректно, так что, когда я нажимаю на одну из вкладок, внимание перемещается на эту вкладку, и она подсвечивается. Однако в версии, использующей цикл for, всякий раз, когда я нажимаю на любую вкладку, внимание всегда перемещается на последнюю вкладку. Чтобы подтвердить происходящее, я распечатал имя элемента внутри прослушивателя событий обоими методами, используя всего 3 вкладки. И используя цикл for, независимо от того, на какую вкладку я нажимаю, я получаю ответ

 "this element: .tabs a:nth-child(3) span"
  

Может кто-нибудь, пожалуйста, помочь мне объяснить, почему это происходит? Почему выходные данные отличаются при использовании for или forEach? И почему при использовании for он всегда передает последний элемент tabs прослушивателю событий?

Комментарии:

1. Вы знаете, что в jQuery есть each встроенная функция?

2. Цикл for проходит через каждый из них <a> , тогда как forEach проходит через каждый <span> в вашем коде.

3. Я действительно знал это. Просто чтобы уточнить, я не спрашиваю, как выполнить эту задачу, поскольку у меня уже есть одно допустимое решение с использованием forEach. Скорее я надеюсь понять несоответствие между методами to, которые должны быть эквивалентны

4. @blex, спасибо за ваши комментарии. В цикле for я получаю доступ к <span> дочернему элементу элемента <a>. Итак, повторяю ли я <span> в обо их случаях? Чтобы пояснить, существует 3 .tabs, и у каждого есть один дочерний элемент <a>, у каждого из которых, в свою очередь, есть 1 <span> вс троенный элемент. Я хочу выполнить итерацию по каждому из 3 <span> элементов.

5. профессиональный совет: Если вы когда-нибудь зациклитесь на том, что делает код, убедитесь, что в нем правильно расставлены отступы. Это облегчает чтение не только вам, но и людям, к которым вы обращаетесь за помощью. Это хорошая привычка, чтобы освоиться сейчас, так как в более крупных проектах вы определенно должны писать читаемый, поддерживаемый код. Надеюсь, это поможет!

Ответ №1:

Похоже, здесь есть проблема:

 var tabSelector = ".tabs a:nth-child(" tabNumber ") span";
$tabSelector.on("click",function(){
  

Вы создали переменную, у которой в начале нет $ , затем прикрепили событие к переменной (не уверен, на что оно будет ссылаться) с $ в начале.

Я считаю, что это должно быть изменено на это:

 $(tabSelector).on("click",function(){
  

Ответ №2:

В for циклическом решении вы устанавливаете tabSelector несколько раз следующим образом:

 var tabSelector = ".tabs a:nth-child(" tabNumber ") span";
  

В конечном итоге для этого селектора будет установлен последний tabNumber, который всегда будет вызываться при создании ссылки на него:

 $(tabSelector).addClass("active");
  

Чтобы избежать этого, замените его на this , который будет отличаться для каждого из них:

 $(this).addClass("active");
  

Демонстрация JS Fiddle

Комментарии:

1. Спасибо, это решение сработало. Удивлен, что в этой книге была ошибка. Итак, если я понимаю, что происходит, цикл for вызывает 3 асинхронных прослушивателя событий в начале, поэтому, когда происходит событие, цикл for уже выполнен и tabSelector установлен в 3. С другой стороны, ключевое слово «this» ссылается на родительский класс, к которому принадлежит функция .on(), то есть на любой tabSelector, соответствующий текущему циклу на момент события. Но «это» также меняется на каждой итерации, поэтому после завершения цикла почему у нас не возникает такой же проблемы с перезаписью?

2. @Paul Я тоже удивлен, но во многих книгах по программированию есть ошибки, которые со временем замечаются и исправляются. Функции onClick объявлены, но не выполняются до тех пор, пока вы не нажмете на вкладку. Таким образом, к тому времени, когда вы нажмете на одну из них, она еще не обработает то, что находится в этой переменной. Когда вы нажимаете, программа видит эту переменную и ищет, на что она ссылается (последняя вкладка). this это переменная, создаваемая на месте при нажатии на вкладку, и, как вы сказали, это ссылка на объект, на который вы нажимаете. Каждый раз, когда вы нажимаете, он будет пытаться решить эту проблему и найти правильный селектор для вас.

3. Хорошо, я думаю, что понимаю: хотя