# 09. Prototype Chain

[Inheritance and the prototype chain](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)

Each object has a private property (referred to as `[[Prototype]]` ) which holds a link to another object called its **prototype**. That prototype object has a prototype of its own, and so on until an object is reached with `null` as its prototype. By definition, `null` has no prototype, and acts as the final link in this **prototype chain**.

## Define object prototype via `__proto__`

Если один объект имеет специальную ссылку `__proto__` на другой объект, то при чтении свойства из него, если свойство отсутствует в самом объекте, оно ищется в объекте `__proto__`.

```javascript
const a = { magic: 42 };
const b = { __proto__: a, super: 55 };
b.super; // => 55
b.magic; // => 42
b.constructor; // => Object
b.__proto__; // => {magic: 42}
b.isPrototypeOf(a); // => false
a.isPrototypeOf(b); // => true
a.__proto__ === Object.prototype; // => true
```

Notice that the usage of `object.__proto__` as a getter/setter is not recommended. Alternatives `Object.getPrototypeOf()` and `Object.setPrototypeOf()` or `Object.create(prototype)` should be considered instead.

* `Object.getPrototypeOf(obj)` - method returns the direct prototype (i.e. the value of the internal `[[Prototype]]` property) of the specified object. `TypeError` if `obj` is not an object.
* `Object.setPrototypeOf(obj, prototype)` - method sets the prototype of a specified object to another object or `null`.

The good part is that ES2015 allows to use the literal `__proto__` as the property name to setup the prototype right in the object literal `{ __proto__: protoObject }`. JavaScript constraints to use only an object or null as a value for `__proto__` property.

```javascript
const myProto = {
  propertyExists(name) {
    return name in this;
  }
};

const myNumbers = {
  __proto__: myProto,
  array: [1, 6, 7]
};

myNumbers.propertyExists("array"); // => true
myNumbers.propertyExists("collection"); // => false
```

The `__proto__` property may not be supported. A simple check for the getter/setter:

```javascript
// Simple check
const supported = {}.hasOwnProperty.call(Object.prototype, "__proto__");

// A more sophisticated check:
const desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
const supported =
  typeof desc.get === "function" && typeof desc.set === "function";
```

Recommendations:

* Use `Object.getPrototypeOf()` to get the prototype of an object.
* Prefer `Object.create()` to create a new object with a given prototype. Avoid `Object.setPrototypeOf()`, which hampers performance on many engines.
* I actually like `__proto__` as an operator in an object literal. It is useful for demonstrating prototypal inheritance and for creating dictionary objects.

## Access to object prototype via `super`

В ES2015 появилось новое ключевое слово `super`, предназначенное только для использования в методах объекта. Вызов `super.parentProperty` позволяет из метода объекта получить свойство его прототипа:

```javascript
const animal = {
  walk() {
    console.log("i am walking");
  }
};

const rabbit = {
  __proto__: animal,

  walk() {
    super.walk();
    console.log("rabbit walk");
  }
};
```

Свойство `super` работает через прототип только в методах объекта. При обращении через `super` используется `[[HomeObject]]` текущего метода, и от него берётся `__proto__`. В частности, если переписать этот код, оформив `rabbit.walk` как обычное свойство-функцию, то будет ошибка. Исключением из этого правила являются функции-стрелки. В них используется `super` внешней функции. Например, здесь функция-стрелка в `setTimeout` берёт внешний `super`:

```javascript
const animal = {
  walk() {
    console.log("I'm walking");
  }
};

const rabbit = {
  __proto__: animal,
  walk() {
    setTimeout(() => super.walk()); // I'm walking
  }
};

rabbit.walk();
```

## Check prototype chain with `obj.isPrototypeOf()`

The `proto.isPrototypeOf(obj)` method checks if an `proto` exists in `obj` object's prototype chain.

```javascript
const proto = {};
const obj = Object.create(proto);
const obj2 = Object.create(obj);

Object.getPrototypeOf(obj) === proto; // => true
Object.getPrototypeOf(obj2) === obj; // => true
Object.getPrototypeOf(obj2) === proto; // => false

obj2.isPrototypeOf(proto); // => false
proto.isPrototypeOf(obj2); // => true

Number.prototype.isPrototypeOf(2); // => false
Number.prototype.isPrototypeOf(new Number(2)); // => true
Number.prototype.isPrototypeOf(Object(2)); // => true
```

## Access to properties

Доступ к любым свойствам объекта выполняется в контексте (наследования) цепочки прототипов.

> Предположим, что программа обращается к свойству `x` объекта `o`. Если объект `o` не имеет собственного свойства с таким именем, выполняется попытка отыскать свойство `x` в прототипе объекта `o`. Если объект-прототип не имеет собственного свойства с этим именем, но имеет свой прототип, выполняется попытка отыскать свойство в прототипе прототипа. Так продолжается до тех пор, пока не будет найдено свойство `x` или пока не будет достигнут объект, не имеющий прототипа.

В цепочке прототипов, свойство объекта с определенным именем перекрывает свойство с таким же именем в его цепочке прототипов, если перекрытие не запрещено.

```javascript
const proto = {
    describe() {
        return 'name: '+ this.name;
    }
};
const obj={
    __proto__: proto,
    name: 'obj'
};

> obj.describe
[Function]

> obj.describe();
"name: obj"

> obj.describe = function () { return 'overridden' };
> obj.describe()
'overridden'
```

При присваивании свойства всегда меняется текущий объект и никогда прототип. Присваивание свойства может не выполниться в некоторых случаях.

Операция присваивания значения свойству проверит наличие этого свойства в цепочке прототипов, чтобы убедиться в допустимости присваивания. Например, если объект `o` наследует свойство `x`, доступное только для чтения, то присваивание выполняться не будет. Однако если присваивание допустимо, всегда создается или изменяется свойство в оригинальном объекте и никогда в цепочке прототипов.&#x20;

Тот факт, что механизм наследования действует при чтении свойств, но не действует при записи новых значений, является ключевой особенностью языка JavaScript, потому что она позволяет выборочно переопределять унаследованные свойства.&#x20;

Существует одно исключение из этого правила, когда операция присваивания значения свойству терпит неудачу. Если объект `o` наследует свойство `x` и доступ к этому свойству осуществляется посредством методов доступа, то вместо создания нового свойства `x` в объекте o производится вызов метода записи нового значения. Однако обратите внимание, что метод записи вызывается относительно объекта `o`, а не относительно прототипа, в котором определено это свойство, поэтому, если метод записи определяет какие-либо свойства, они будут созданы в объекте `o`, а цепочка прототипов опять останется неизменной.

## Dictionaries

Объекты без прототипа часто называются *картами* или *dictionary pattern*:

```javascript
const dict = Object.create(null);
```

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


---

# 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/09-object-prototype.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.
