# 06. Object Iteration

* **Перечисляемые свойства** --- это те свойства, для которых внутренний атрибут ключа выставлен в `enumerable = true`. Перечисляемые свойства можно перебрать в цикле `for..in`, за исключением полей-символов.
* **Принадлежность свойства** определяется тем, принадлежит ли свойство самому объекту, или находится в его цепочке прототипов.
  * *Собственные свойства* принадлежат самому объекту, а
  * *Унаследованные свойства* принадлежат его прототипу.

В ES6 порядок перебора ключей стандартизирован:

* Все индексы массивов, отсортированные по возрастанию. Индекс массива - специальный ключ-строка, хранящий число `0..2^32−1`.
* Все строковые ключи, в том порядке, в котором они объявлены.
* Все символы, в том порядке в котором они объявлены.

В зависимости от способа перечисления можно получить разные свойства:

![alt text](/files/-M5buQW5FF_-5095zXr_)

## `for-in`

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

```javascript
const obj = { a: 1, b: 2, c: 3 };
for (const prop in obj) {
  console.log("obj." + prop + " = " + obj[prop]);
}
```

Особенности:

* Порядок не определен
* Перечисляются так же и наследуемые свойства по всей цепочке прототипов.
* Если необходимо перечислять только собственные свойства объекта, их необходимо фильтровать
* Если свойство объекта отмечено как `enumerable: false`, то оно не будет встречаться в цикле.
* В теле цикла можно изменять объект, а так же удалять его свойства.

## `hasOwnProperty` guard

Common pattern consisting of `for..in` with `Object.prototype.hasOwnProperty` guards:

```javascript
const obj = {
  x: 1,
  y: 1,
  z: 1
};
const total = 0;
for (const prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    total += obj[prop];
  }
}
```

Note that in this particular case, the `Object#hasOwnProperty` guard is not used properly, because the lookup happens on the `obj` itself, which leads to potential performance issues, i.e. if you pass many different shapes of objects then the `obj.hasOwnProperty` access will become megamorphic, but might also turn into a correctness issue, i.e. if `obj` has a `null` prototype because `obj` was created via `Object.create(null)`, then the expression `obj.hasOwnProperty` will raise an error. So make sure to always follow the advice to write `Object.prototype.hasOwnProperty.call(obj, prop)` instead, which is safe and avoids the potential negative performance impact:

```javascript
const obj = {
  x: 1,
  y: 1,
  z: 1
};
const total = 0;
for (const prop in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, prop)) {
    total += obj[prop];
  }
}
```

## `for-of`

Конструкция `for..of` в начале своего выполнения автоматически вызывает `Symbol.iterator()`, получает итератор и далее вызывает метод `next()` до получения done: `true`. Если функционал по перебору (метод `next`) предоставляется самим объектом, то можно вернуть `this` в качестве итератора:

```javascript
// Throw Error
const obj = { a: 1, b: 2, c: 3 };
for (const prop of obj) {
  console.log("obj." + prop + " = " + obj[prop]);
}

// Ok
const obj = { a: 1, b: 2, c: 3 };
for (const [key, value] of Object.entries(obj)) {
  console.log("obj." + key + " = " + value);
}
```

Создание собственного итератора:

```javascript
const range = {
    from: 1,
    to: 5,

    [Symbol.iterator]() {
        return this;
    },

    next() {
        ...
    }
};

for (let num of range) {
    console.log(num); // 1, затем 2, 3, 4, 5
}
```

## `Object.keys()`, `Object.values()`

`Object.keys() : Array<string>` --- возвращает массив имен собственных перечислимых свойств объекта.

```javascript
const arr = ["a", "b", "c"];
Object.keys(arr); // console: ['0', '1', '2']

// array like object
const obj = { 0: "a", 1: "b", 2: "c" };
Object.keys(obj); // console: ['0', '1', '2']

// array like object with random key ordering
const an_obj = { 100: "a", 2: "b", 7: "c" };
Object.keys(an_obj); // console: ['2', '7', '100']

// getFoo is property which isn't enumerable
const my_obj = Object.create(
  {},
  {
    getFoo: {
      value: function() {
        return this.foo;
      }
    }
  }
);
my_obj.foo = 1;

Object.keys(my_obj); // console: ['foo']
```

Не возвращает унаследованные свойства

```javascript
const simpleColors = {
  colorA: "white",
  colorB: "black"
};
const natureColors = {
  colorC: "green",
  colorD: "yellow"
};

Object.setPrototypeOf(natureColors, simpleColors);
Object.keys(natureColors); // => ['colorC', 'colorD']

natureColors["colorA"]; // => 'white'
natureColors["colorB"]; // => 'black'
```

Похожие функции, работающие по тем же принципам:

* `Object.values`
* `Object.entries`

## `Object.getOwnPropertyNames()`

`Object.getOwnPropertyNames() : Array<string>` - действует подобно функции `Object.keys()`, но возвращает имена всех собственных свойств указанного объекта, а не только перечислимые. Порядок свойств такой же, как при ручном переборе объекта в цикле.

```javascript
const arr = ["a", "b", "c"];
Object.getOwnPropertyNames(arr).sort(); // logs '0,1,2,length'

// Array-like object
const obj = { 0: "a", 1: "b", 2: "c" };
Object.getOwnPropertyNames(obj).sort(); // logs '0,1,2'

// non-enumerable property
const my_obj = Object.create(
  {},
  {
    getFoo: {
      value: function() {
        return this.foo;
      },
      enumerable: false
    }
  }
);
my_obj.foo = 1;

Object.getOwnPropertyNames(my_obj).sort(); // logs 'foo,getFoo'
```

Похожие методы:

* `Object.getOwnPropertySymbols(obj) : Array<symbol>` -- возвращает все собственные ключи-символы объекта.
* `Reflect.ownKeys(obj) : Array<string|symbol>` --- возвращает все ключи всех свойств объекта.
* `Reflect.enumerate(obj) : Iterator` - возвращает все строковые значения всех перечисляемых свойств.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://strctr.gitbook.io/programming/01-languages/javascript/01-language/b-structured/b2-objects/06-object-iteration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
