en.javascript.info/1-js/4-data-structures/4-object-for-in/article.md
Ilya Kantor 87bf53d076 update
2014-11-16 01:40:20 +03:00

173 lines
7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Объекты: перебор свойств
Для перебора всех свойств из объекта используется цикл по свойствам `for..in`. Это специальная синтаксическая конструкция, которая работает не так, как обычный цикл.
[cut]
## for..in [#for..in]
Синтаксис:
```js
for (key in obj) {
/* ... делать что-то с obj[key] ... */
}
```
При этом в `key` будут последовательно записаны имена свойств. Конечно, вместо `key` может быть любое другое имя переменной.
[smart header="Объявление переменной в цикле `for (var key in obj)`"]
Переменную можно объявить прямо в цикле:
```js
for (*!*var key*/!* in menu) {
// ...
}
```
Так иногда пишут для краткости кода.
[/smart]
Например:
```js
//+ run
var menu = {
width: 300,
height: 200,
title: "Menu"
};
for (var key in menu) {
// этот код будет вызван для каждого свойства объекта
// ..и выведет имя свойства и его значение
*!*
alert("Ключ: " + key + " значение:" + menu[key]);
*/!*
}
```
Обратите внимание, мы использовали квадратные скобки `menu[key]`. Как уже говорилось, если имя свойства хранится в переменной, то обратиться к нему можно только так, не через точку.
## Количество свойств в объекте
Как узнать, сколько свойств хранит объект?
Готового метода для этого нет.
Самый кросс-браузерный способ -- это сделать цикл по свойствам и посчитать, вот так:
```js
//+ run
var menu = {
width: 300,
height: 200,
title: "Menu"
};
*!*
var counter = 0;
for (var key in menu) {
counter++;
}
*/!*
alert("Всего свойств: " + counter);
```
В следующих главах мы пройдём массивы и познакомимся с другим, более коротким, вызовом: `Object.keys(menu).length`.
## В каком порядке перебираются свойства?
Для примера, рассмотрим объект, который задаёт список опций для выбора страны:
```js
var codes = {
// телефонные коды в формате "код страны": "название"
"7": "Россия",
"38": "Украина",
// ..,
"1": "США"
};
```
Здесь мы предполагаем, что большинство посетителей из России, и поэтому начинаем с `7`, это зависит от проекта.
При выборе телефонного кода мы хотели бы предлагать варианты, начиная с первого. Обычно на основе списка генерируется `select`, но здесь нам важно не это, а важно другое.
**Правда ли, что при переборе `for(key in codes)` ключи `key` будут перечислены именно в том порядке, в котором заданы?**
**По стандарту -- нет. Но некоторое соглашение об этом, всё же, есть.**
Соглашение говорит, что если имя свойства -- нечисловая строка, то такие ключи всегда перебираются в том же порядке. Так получилось по историческим причинам и изменить это сложно: поломается много готового кода.
С другой стороны, если имя свойства -- число, то все современные браузеры сортируют такие свойства в целях внутренней оптимизации.
К примеру, рассмотрим объект с заведомо нечисловыми свойствами:
```js
//+ run
var user = {
name: "Вася",
surname: "Петров"
};
user.age = 25;
*!*
// порядок перебора соответствует порядку присвоения свойства
*/!*
for (var prop in user) {
alert(prop); // name, surname, age
}
```
А теперь -- что будет, если перебрать объект с кодами?
```js
//+ run
var codes = {
// телефонные коды в формате "код страны": "название"
"7": "Россия",
"38": "Украина",
"1": "США"
};
for(var code in codes) alert(code); // 1, 7, 38
```
При запуске этого кода в современном браузере мы увидим, что на первое место попал код США!
Нарушение порядка возникло, потому что ключи численные. Интерпретатор JavaScript видит, что строка на самом деле является числом и преобразует ключ в немного другой внутренний формат. Дополнительным эффектом внутренних оптимизаций является сортировка.
**А что, если мы хотим, чтобы порядок был именно таким, какой мы задали?**
Это возможно. Можно применить небольшой хак, который заключается в том, чтобы сделать все ключи нечисловыми, например, добавим в начало дополнительный символ `'+'`:
```js
//+ 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 во всех браузерах
}
```
## Итого
<ul>
<li>Цикл по ключам: `for (key in obj)`.</li>
<li>Порядок перебора соответствует порядку объявления для нечисловых ключей, а числовые -- сортируются (в современных браузерах).</li>
<li>Для того, чтобы гарантировать перебор ключей в нужном порядке, их делают "нечисловыми", например добавляя в начало `+`, а потом, в процессе обработки, преобразуют ключи в числа.</li>
</ul>