en.javascript.info/1-js/4-data-structures/5-object-for-in/article.md
2015-01-11 01:54:57 +03:00

7.2 KiB
Raw Blame History

Объекты: перебор свойств

Для перебора всех свойств из объекта используется цикл по свойствам for..in. Эта синтаксическая конструкция отличается от рассмотренного ранее цикла for(;;).

[cut]

for..in [#for..in]

Синтаксис:

for (key in obj) { 
  /* ... делать что-то с obj[key] ... */
}

При этом for..in последовательно переберёт свойства объекта obj, имя каждого свойства будет записано в key и вызвано тело цикла.

[smart header="Объявление переменной в цикле for (var key in obj)"] Вспомогательную переменную key можно объявить прямо в цикле:

for (*!*var key*/!* in menu) { 
  // ...
}

Так иногда пишут для краткости кода. Можно использовать и любое другое название, кроме key, например for(var propName in menu). [/smart]

Пример итерации по свойствам:

//+ run
var menu = {
    width:  300,
    height: 200,
    title: "Menu"
};

for (var key in menu) { 
    // этот код будет вызван для каждого свойства объекта    
    // ..и выведет имя свойства и его значение

*!*
    alert("Ключ: " + key + " значение:" + menu[key]);
*/!*
}

Обратите внимание, мы использовали квадратные скобки menu[key]. Как уже говорилось, если имя свойства хранится в переменной, то обратиться к нему можно только так, не через точку.

Количество свойств в объекте

Как узнать, сколько свойств хранит объект?

Готового метода для этого нет.

Самый кросс-браузерный способ -- это сделать цикл по свойствам и посчитать, вот так:

//+ run
var menu = {
    width:  300,
    height: 200,
    title: "Menu"
};

*!*
var counter = 0;

for (var key in menu) {
  counter++;
}
*/!*

alert("Всего свойств: " + counter);

В следующих главах мы пройдём массивы и познакомимся с другим, более коротким, вызовом: Object.keys(menu).length.

В каком порядке перебираются свойства?

Для примера, рассмотрим объект, который задаёт список опций для выбора страны:

var codes = {
  // телефонные коды в формате "код страны": "название"
  "7": "Россия",
  "38": "Украина",
  // ..,
  "1": "США"
};

Здесь мы предполагаем, что большинство посетителей из России, и поэтому начинаем с 7, это зависит от проекта.

При выборе телефонного кода мы хотели бы предлагать варианты, начиная с первого. Обычно на основе списка генерируется select, но здесь нам важно не это, а важно другое.

Правда ли, что при переборе for(key in codes) ключи key будут перечислены именно в том порядке, в котором заданы?

По стандарту -- нет. Но некоторое соглашение об этом, всё же, есть.

Соглашение говорит, что если имя свойства -- нечисловая строка, то такие ключи всегда перебираются в том же порядке. Так получилось по историческим причинам и изменить это сложно: поломается много готового кода.

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

К примеру, рассмотрим объект с заведомо нечисловыми свойствами:

//+ run
var user = {
  name: "Вася",
  surname: "Петров"
};
user.age = 25;

*!*
// порядок перебора соответствует порядку присвоения свойства
*/!*
for (var prop in user) {
  alert(prop); // name, surname, age
}

А теперь -- что будет, если перебрать объект с кодами?

//+ run
var codes = {
  // телефонные коды в формате "код страны": "название"
  "7": "Россия",
  "38": "Украина",
  "1": "США"
};

for(var code in codes) alert(code); // 1, 7, 38

При запуске этого кода в современном браузере мы увидим, что на первое место попал код США!

Нарушение порядка возникло, потому что ключи численные. Интерпретатор JavaScript видит, что строка на самом деле является числом и преобразует ключ в немного другой внутренний формат. Дополнительным эффектом внутренних оптимизаций является сортировка.

А что, если мы хотим, чтобы порядок был именно таким, какой мы задали?

Это возможно. Можно применить небольшой хак, который заключается в том, чтобы сделать все ключи нечисловыми, например, добавим в начало дополнительный символ '+':

//+ run
var codes = {
  "+7": "Россия", 
  "+38": "Украина",
  "+1": "США"
};

for (var code in codes ) {
  var value = codes[code];
  code = +code; // ..если нам нужно именно число, преобразуем: "+7" -> 7
 
  alert( code + ": " + value ); // 7, 38, 1 во всех браузерах
}

Итого

  • Цикл по ключам: `for (key in obj)`.
  • Порядок перебора соответствует порядку объявления для нечисловых ключей, а числовые -- сортируются (в современных браузерах).
  • Для того, чтобы гарантировать перебор ключей в нужном порядке, их делают "нечисловыми", например добавляя в начало `+`, а потом, в процессе обработки, преобразуют ключи в числа.