Правильное использование цикла "for... in" в javascript?

прежде чем задавать свой вопрос, я хотел, чтобы все знали, что я ценю тот факт, что всегда кто-то там готов помочь, и в конце концов я постараюсь вернуть сообщество настолько, насколько смогу. Благодаря

Теперь я хотел бы получить несколько указаний относительно того, как правильно использовать цикл "for... in" в JavaScript, я уже провел некоторое исследование и попробовал пару вещей, но мне все еще не ясно как правильно его использовать.

Скажем, у меня есть случайное число тегов "select" в HTML-форме, и я не требую от пользователя выбора опции для всех из них, они могут оставить некоторые нетронутые, если они захотят. Однако мне нужно знать, выбрали ли они ни одного или хотя бы одного.

То, как я пытаюсь выяснить, выбрал ли пользователь какой-либо из них, используется цикл "for... in". Например:

var allSelected = $("select option:selected");
var totalSelected = $("select option:selected").length;

Первая переменная создает массив всех выбранных параметров. Вторая переменная сообщает мне, сколько выбранных параметров у меня есть в форме (выбор тегов может быть более одного, и он изменяется каждый раз). Теперь, чтобы увидеть, был ли выбран какой-либо элемент, я просматриваю каждый элемент (выбранный параметр) и извлекаю атрибут "значение". По умолчанию тег "option" имеет value = "0", поэтому, если какой-либо выбранный параметр возвращает значение больше 0, я знаю, что выбран хотя бы один параметр, однако он не должен быть в порядке, это мой цикл пока:

for(var i = 0; i < totalSelected; i++){
  var eachOption = $(allSelected[i]).val();
  var defaultValue = 0;
  if(eachOption == defaultValue){
    ...redirect to another page
  }else if(eachOption > defaultValue){
    ... I display an alert
  }
}

Моя проблема заключается в том, что как только "if" соответствует значению 0, он отправляет пользователя на следующую страницу, не тестируя остальные элементы в массиве, и пользователь мог выбрать второй или третий варианты.

То, что я действительно хочу сделать, это проверить все элементы в массиве, а затем сделать следующее действие, на мой взгляд, так я могу это сделать, но я не понимаю:

var randomValue = 25;  
for(randomValue in allSelected){
  var found = true;
  var notFound = false
  if(found){
    display an alert
  }else{
    redirect to next page
  }
}

Этот цикл или логика, которую я использую, являются ошибочными (я уверен), то, что я хочу сделать, это проверить все элементы в массиве на одну переменную и соответственно выполнить следующее действие.

Надеюсь, это смущает вас, ребята, любая помощь будет оценена. Спасибо,
JC

Ответ 1

Простейший способ написать (что я думаю) пытаюсь достичь с помощью .each()

// this is to know if we want to redirect
var redir = true;
$("select option:selected").each(function() {
  var val = $(this).val();

  if (val > 0) {
    alert('Found one!');
  }      
  if (val != 0) { 
    redir = false;
    // you can return false here if you want to stop processing the each loop too!
  } 
});

if (redir) {
  window.location = "/nextpage";
}

Ответ 2

for..in(обычно)

for..in перебирает имена свойств объекта. Люди думают, что это петли через индексы массива, потому что индексы массива являются именами свойств объекта массива, но это неправильное представление.

Итак:

var obj = {foo: 1, bar: 2};

foo и bar - имена свойств, и поэтому:

var name;
for (name in obj) {
    alert(name);
}

... покажет "foo" и "bar" (в определенном порядке).

Мы вернемся к массивам через мгновение.:-) Посмотрите сначала на объекты.

Объекты могут иметь собственные свойства и свойства, которые они наследуют от своих объектов-прототипов. Приведенные выше свойства foo и bar были прямыми свойствами obj, но:

function Thing() {
}
Thing.prototype.foo = 1;

var t = new Thing();
t.bar = 2;

Теперь наш объект t имеет foo и bar, но foo исходит из прототипа, тогда как bar является его собственным свойством. В a for..in мы можем проверить, что именно:

var name;
for (name in obj) {
    alert(name + "(" + (obj.hasOwnProperty(name) ? "own" : "inherited") + ")");
}

..., который покажет "foo (inherited)" и "bar (собственный)" (в определенном порядке).

Объекты могут также иметь свойства, которые не перечислены — они не отображаются в циклах for..in. Вот почему, если вы делаете for..in в массиве, свойство length не отображается, потому что length определяется как неперечислимое свойство. Почти все стандартные свойства стандартных объектов неперечислимы (включая все те, которые указывают на функции, такие как свойство toUpperCase в экземплярах String). (Раньше считалось, что только те, что были в спецификации, не подлежат перечислению, но в пятом выпуске ECMAScript теперь есть способы для наших собственных неперечислимых свойств.)

Итак, массивы. Массивы в Javascript не похожи на массивы на большинстве других языков. (Они не являются непрерывными блоками памяти, с одной стороны.) Массив в Javascript является стандартным объектом с несколькими особыми формами поведения:

  • Свойству length всегда присваивается следующее число над именем свойства с самым большим числовым значением, которое имеют объекты массива. Поэтому, если ваш самый высокий индекс массива 2, то length будет равно 3.
  • Если вы измените length, любое свойство, чье имя имеет числовое значение, равное или превышающее число, которое вы даете length, будет удалено из объекта.

Это и функции, которые они наследуют от Array.prototype, в значительной степени относятся к массивам в Javascript. Все их основные функции (сохранение и получение значений) - это просто стандартное поведение свойства объекта Javascript.

Конкретный цикл

По вышеуказанным причинам я бы не использовал for..in для вашего цикла. Я либо использовал бы jQuery#each, либо скучный старомодный цикл, как и у вас. Последний будет выглядеть так:

var allSelected = $("select option:selected");
var totalSelected = allSelected.length; // <= No need to repeat the selector query
var index;
var anySelected = false;
for (index = 0; !anySelected && index < totalSelected; ++index) {
    if (allSelected[index].value !== "0") {
        anySelected = true;
    }
}
if (anySelected) {
    // do something with the selection
}
else [
    // do something about their not having picked one
}

Ответ 3

Вы должны знать, что оператор for-in в JavaScript предназначен для перечислять свойства объекта.

Если вы хотите итерации над массивом типа 1 последовательный цикл (for, while, do...while).

Почему вы не должны использовать for-in для объектов типа массива:

  • Порядок итераций не гарантируется
  • Унаследованные свойства также перечислены

См. также:

[1] Под массивом я подразумеваю любой объект, содержащий последовательно пронумерованные свойства и свойство length.

Ответ 4

В вашем вопросе есть два аспекта.

  • Используйте "for... in" только для прокрутки имен свойств объектов и никогда не перебирайте массивы (либо реальные массивы, либо вещи, которые являются более или менее похожими массивами, такими как jQuery объекты).

  • Если вы используете jQuery, это противоречит идиоматическому действию в этом отношении:

    $("select option:selected).each(function() {
      // .. "this" points to each option
    });

Если вы хотите собрать все настройки всех выбранных, вы можете выполнять итерацию по всем тегам <select>, отфильтровывать те, которые установлены только на их значение по умолчанию, а затем собирать все значения в имя/значение пары.

Ответ 5

Я сделал бы что-то вроде этого

<html>
<head>
  <title>Test Page</title>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
  <script type="text/javascript">

  $(function()
  {
    function checkSelected()
    {
      var DEFAULT = "0";
      var selected = [];

      $("select option:selected").each( function()
      {
        var $option = $(this);
        var optionValue = $option.val(); 
        if ( optionValue !== DEFAULT )
        {
          selected.push( {name: $option.parent().attr( 'name' ), value: optionValue } );
        }
      });

      if ( selected.length )
      {
        $.each( selected, function( index, item )
        {
          alert( item.name + ': ' + item.value );        
        });
      } else {
        alert( 'None selected!' );
      }
    }

    // just for this demo
    $('button').click( function( event )
    {
      event.preventDefault();
      checkSelected();
    })
  });


  </script>
</head>

<body>

<select name="one">
  <option value="0">Zero</option>
  <option value="1">One</option>
</select>

<select name="two">
  <option value="0">Zero</option>
  <option value="1">One</option>
</select>

<button>Test It</button>

</body>
</html>