Object.prototype.\_\_proto\_\_
==============================

**Предупреждение:** Изменение прототипа `[[Prototype]]` объекта является, по самой природе оптимизации доступа к свойствам в современных движках JavaScript, очень медленной операцией, это справедливо для ***любого*** браузера и движка JavaScript. Изменение прототипов очень тонко и обширно влияет на производительность, причём это влияние не ограничивается просто временем для операции присваивания `obj.__proto__ = ...`, оно может распространяться на ***любой*** код, который имеет доступ к ***любому*** объекту, чей прототип `[[Prototype]]` был изменён. Если вы заботитесь о производительности, вы никогда не должны изменять прототип `[[Prototype]]` объекта. Вместо этого создайте объект с нужным прототипом `[[Prototype]]`, с помощью метода `Object.create()`.

**Предупреждение:** хотя на сегодняшний момент большинство браузеров поддерживают свойство `Object.prototype.__proto__`, его поведение только недавно было стандартизировано в новой спецификации ECMAScript 6. Если вам требуется поддержка браузеров до этой спецификации, рекомендуется использовать вместо него метод `Object.getPrototypeOf()`.

Сводка
------

Свойство `__proto__` объекта `Object.prototype` (en-US) является свойством доступа (комбинацией геттера и сеттера), которое расширяет внутренний прототип `[[Prototype]]` объекта (являющийся объектом или `null`), через который осуществлялся доступ.

Использование свойства `__proto__` вызывает споры и многих оно разочаровало. Ранее оно никогда не включалось в спецификацию EcmaScript, но современные браузеры всё равно решили его реализовать. Сегодня свойство `__proto__` стандартизировано в спецификации ECMAScript 6 и будет поддерживаться в будущем. Тем не менее, изменение прототипа `[[Prototype]]` объекта всё ещё остаётся медленной операцией, которую следует избегать, если вы беспокоитесь о производительности.

Свойство `__proto__` также может использоваться при определении литерала объекта, устанавливая прототип `[[Prototype]]` объекта при его создании. Этот способ может рассматриваться как альтернатива методу `Object.create()`. Смотрите также литеральный синтаксис инициализации объекта.

Синтаксис
---------


```js
var shape = {},
  circle = new Circle();

// Установка прототипа объекта
shape.__proto__ = circle;
// Получение прототипа объекта
console.log(shape.__proto__ === circle); // true
```


Обратите внимание: название свойства состоит из двух подчёркиваний, следующих за ними пяти символов «proto» и следующих за ними ещё двух подчёркиваний.

Описание
--------

Геттер свойства `__proto__` расширяет значение внутреннего прототипа `[[Prototype]]` объекта. Для объектов, созданных с использованием литеральной формы создания объекта, это значение равно `Object.prototype` (en-US). Для функций это значение равно `Function.prototype` (en-US). Для объектов, созданных с использованием формы `new fun`, где `fun` является одной из встроенных функций-конструкторов, предоставляемых JavaScript (`Array`, `Boolean`, `Date`, `Number`, `Object`, `String` и так далее — включая новые конструкторы, добавленные в процессе развития JavaScript), это значение равно `fun.prototype`. Для объектов, созданных с использованием формы `new fun`, где `fun` является функцией, определённой в скрипте, это значение равно значению `fun.prototype` во время вычисления `new fun`. Именно поэтому при присваивании `fun.prototype` нового значения, ранее созданные экземпляры `fun` продолжат использовать предыдущее значение в качестве своего прототипа `[[Prototype]]`, а последующие вызовы `new fun` будут использовать вновь присвоенное значение в качестве своего прототипа `[[Prototype]]`.

Геттер `__proto__` позволяет прототипу `[[Prototype]]` объекта быть изменяемым. Объект должен быть расширяемым в соответствии с `Object.isExtensible()`: если это не так, выкидывается исключение `TypeError`. Предоставляемое значение должно быть объектом или `null`. Предоставление любого другого значения ничего не даст.

Для понимания того, как прототипы используются для наследования, смотрите статью руководства «Наследование и цепочки прототипов».

Свойство `__proto__` является простым свойством доступа на объекте `Object.prototype` (en-US) — свойством, состоящим из геттера и сеттера. Свойство `__proto__` будет найдено, если, в конечном итоге, его поиск пройдёт через `Object.prototype` (en-US), но при доступе к нему не через `Object.prototype` (en-US), оно найдено не будет. Если перед просмотром `Object.prototype` (en-US) буден найдено какое-нибудь другое свойство `__proto__`, оно скроет искомое свойство `Object.prototype` (en-US).


```js
var noProto = Object.create(null);

console.log(typeof noProto.__proto__); // undefined
console.log(Object.getPrototypeOf(noProto)); // null

noProto.__proto__ = 17;

console.log(noProto.__proto__); // 17
console.log(Object.getPrototypeOf(noProto)); // null

var protoHidden = {};
Object.defineProperty(protoHidden, "\_\_proto\_\_", {
  value: 42,
  writable: true,
  configurable: true,
  enumerable: true,
});

console.log(protoHidden.__proto__); // 42
console.log(Object.getPrototypeOf(protoHidden) === Object.prototype); // true
```

Примеры
-------

В следующем примере создаётся новый экземпляр `Employee`, а затем проверяется, что его свойство `__proto__` является тем же самым объектом, что и его конструктор `prototype`.


```js
// Декларируем функцию, используемую как конструктор
function Employee() {
  /\* инициализируем экземпляр \*/
}

// Создаём новый экземпляр Employee
var fred = new Employee();

// Проверка на эквивалентность
fred.__proto__ === Employee.prototype; // true
```


В этот момент `fred` унаследован от `Employee`, однако присваивание другого объекта в `fred.__proto__` может изменить это:


```js
function Cow() {
  /\* инициализируем экземпляр \*/
}

// Присваиваем \_\_proto\_\_ новый объект
fred.__proto__ = Cow.prototype;
```


Теперь `fred` наследуется непосредственно от `Cow.prototype`, а не от `Employee.prototype`, и теряет свойства, изначально унаследованные от `Employee.prototype`.

Однако, это применяется только к расширяемым объектам, у нерасширяемых объектов свойство `__proto__` не может быть изменено:


```js
var obj = {};
Object.preventExtensions(obj);

obj.__proto__ = {}; // выкинет TypeError
```


Обратите внимание, что свойство `__proto__` может быть переопределено даже у объекта `Object.prototype`, если новая цепочка заканчивается `null`:


```js
var b = {};

Object.prototype.__proto__ = Object.create(
  null, // [[Prototype]]
  {
    hi: {
      value: function () {
        alert("hi");
      },
    },
  },
);

b.hi();
```


Если свойство `__proto__` объекта `Object.prototype` (en-US) не установлено в `null`, или в другой объект, чья цепочка прототипов, в конечном итоге, явно не заканчивается значением `null`, будет выкинуто исключение `TypeError` «циклическое значение \_\_proto\_\_», поскольку цепочка должна заканчиваться `null` (как это и происходит на `Object.prototype` (en-US) при нормальных обстоятельствах).

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-object.prototype.\_\_proto\_\_ |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

**Примечание:** спецификация ES6 требует поддержку свойства `__proto__` только в браузерах и не требует его поддержку в других окружениях (хотя оно и рекомендуется в качестве обязательного). Если ваш код должен работать в не-браузерных окружениях, вместо свойства рекомендуется использовать методы `Object.getPrototypeOf()` и `Object.setPrototypeOf()`.

Смотрите также
--------------

* `Object.prototype.isPrototypeOf()`
* `Object.getPrototypeOf()`
* `Object.setPrototypeOf()`