173 lines
7 KiB
Markdown
173 lines
7 KiB
Markdown
# Объекты: перебор свойств
|
||
|
||
Для перебора всех свойств из объекта используется цикл по свойствам `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>
|
||
|