1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
---
title: Object.prototype.__proto__
slug: Web/JavaScript/Reference/Global_Objects/Object/proto
tags:
- JavaScript
- Object
- Property
- Prototype
- Reference
- Référence(2)
translation_of: Web/JavaScript/Reference/Global_Objects/Object/proto
---
<div>{{JSRef("Global_Objects", "Object")}}</div>
<div class="warning">
<p><strong>Предупреждение:</strong> Изменение прототипа <code>[[Prototype]]</code> объекта является, по самой природе оптимизации доступа к свойствам в современных движках JavaScript, очень медленной операцией, это справедливо для <strong><em>любого</em></strong> браузера и движка JavaScript. Изменение прототипов очень тонко и обширно влияет на производительность, причём это влияние не ограничивается просто временем для операции присваивания <code>obj.__proto__ = ...</code>, оно может распространяться на <strong><em>любой</em></strong> код, который имеет доступ к <strong><em>любому</em></strong> объекту, чей прототип <code>[[Prototype]]</code> был изменён. Если вы заботитесь о производительности, вы никогда не должны изменять прототип <code>[[Prototype]]</code> объекта. Вместо этого создайте объект с нужным прототипом <code>[[Prototype]]</code>, с помощью метода {{jsxref("Object.create()")}}.</p>
</div>
<div class="warning">
<p><strong>Предупреждение:</strong> хотя на сегодняшний момент большинство браузеров поддерживают свойство <code>Object.prototype.__proto__</code>, его поведение только недавно было стандартизировано в новой спецификации ECMAScript 6. Если вам требуется поддержка браузеров до этой спецификации, рекомендуется использовать вместо него метод {{jsxref("Object.getPrototypeOf()")}}.</p>
</div>
<h2 id="Summary">Сводка</h2>
<p>Свойство <code>__proto__</code> объекта {{jsxref("Object.prototype")}} является свойством доступа (комбинацией геттера и сеттера), которое расширяет внутренний прототип <code>[[Prototype]]</code> объекта (являющийся объектом или {{jsxref("Global_Objects/null", "null")}}), через который осуществлялся доступ.</p>
<p>Использование свойства <code>__proto__</code> вызывает споры и многих оно разочаровало. Ранее оно никогда не включалось в спецификацию EcmaScript, но современные браузеры всё равно решили его реализовать. Сегодня свойство <code>__proto__</code> стандартизировано в спецификации ECMAScript 6 и будет поддерживаться в будущем. Тем не менее, изменение прототипа <code>[[Prototype]]</code> объекта всё ещё остаётся медленной операцией, которую следует избегать, если вы беспокоитесь о производительности.</p>
<p>Свойство <code>__proto__</code> также может использоваться при определении литерала объекта, устанавливая прототип <code>[[Prototype]]</code> объекта при его создании. Этот способ может рассматриваться как альтернатива методу {{jsxref("Object.create()")}}. Смотрите также <a href="/ru/docs/Web/JavaScript/Reference/Operators/Object_initializer">литеральный синтаксис инициализации объекта</a>.</p>
<h2 id="Syntax">Синтаксис</h2>
<pre class="brush: js">var shape = {}, circle = new Circle();
// Установка прототипа объекта
shape.__proto__ = circle;
// Получение прототипа объекта
console.log(shape.__proto__ === circle); // true
</pre>
<p>Обратите внимание: название свойства состоит из двух подчёркиваний, следующих за ними пяти символов «proto» и следующих за ними ещё двух подчёркиваний.</p>
<h2 id="Description">Описание</h2>
<p>Геттер свойства <code>__proto__</code> расширяет значение внутреннего прототипа <code>[[Prototype]]</code> объекта. Для объектов, созданных с использованием литеральной формы создания объекта, это значение равно {{jsxref("Object.prototype")}}. Для функций это значение равно {{jsxref("Function.prototype")}}. Для объектов, созданных с использованием формы <code>new fun</code>, где <code>fun</code> является одной из встроенных функций-конструкторов, предоставляемых JavaScript ({{jsxref("Global_Objects/Array", "Array")}}, {{jsxref("Global_Objects/Boolean", "Boolean")}}, {{jsxref("Global_Objects/Date", "Date")}}, {{jsxref("Global_Objects/Number", "Number")}}, {{jsxref("Global_Objects/Object", "Object")}}, {{jsxref("Global_Objects/String", "String")}} и так далее — включая новые конструкторы, добавленные в процессе развития JavaScript), это значение равно <code>fun.prototype</code>. Для объектов, созданных с использованием формы <code>new fun</code>, где <code>fun</code> является функцией, определённой в скрипте, это значение равно значению <code>fun.prototype</code> во время вычисления <code>new fun</code>. Именно поэтому при присваивании <code>fun.prototype</code> нового значения, ранее созданные экземпляры <code>fun</code> продолжат использовать предыдущее значение в качестве своего прототипа <code>[[Prototype]]</code>, а последующие вызовы <code>new fun</code> будут использовать вновь присвоенное значение в качестве своего прототипа <code>[[Prototype]]</code>.</p>
<p>Геттер <code>__proto__</code> позволяет прототипу <code>[[Prototype]]</code> объекта быть изменяемым. Объект должен быть расширяемым в соответствии с {{jsxref("Object.isExtensible()")}}: если это не так, выкидывается исключение {{jsxref("Global_Objects/TypeError", "TypeError")}}. Предоставляемое значение должно быть объектом или {{jsxref("Global_Objects/null", "null")}}. Предоставление любого другого значения ничего не даст.</p>
<p>Для понимания того, как прототипы используются для наследования, смотрите статью руководства <a href="/ru/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">«Наследование и цепочки прототипов»</a>.</p>
<p>Свойство <code>__proto__</code> является простым свойством доступа на объекте {{jsxref("Object.prototype")}} — свойством, состоящим из геттера и сеттера. Свойство <code>__proto__</code> будет найдено, если, в конечном итоге, его поиск пройдёт через {{jsxref("Object.prototype")}}, но при доступе к нему не через {{jsxref("Object.prototype")}}, оно найдено не будет. Если перед просмотром {{jsxref("Object.prototype")}} буден найдено какое-нибудь другое свойство <code>__proto__</code>, оно скроет искомое свойство {{jsxref("Object.prototype")}}.</p>
<pre class="brush: 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
</pre>
<h2 id="Examples">Примеры</h2>
<p>В следующем примере создаётся новый экземпляр <code>Employee</code>, а затем проверяется, что его свойство <code>__proto__</code> является тем же самым объектом, что и его конструктор <code>prototype</code>.</p>
<pre class="brush: js">// Декларируем функцию, используемую как конструктор
function Employee() {
/* инициализируем экземпляр */
}
// Создаём новый экземпляр Employee
var fred = new Employee();
// Проверка на эквивалентность
fred.__proto__ === Employee.prototype; // true
</pre>
<p>В этот момент <code>fred</code> унаследован от <code>Employee</code>, однако присваивание другого объекта в <code>fred.__proto__</code> может изменить это:</p>
<pre class="brush: js">function Cow() {
/* инициализируем экземпляр */
}
// Присваиваем __proto__ новый объект
fred.__proto__ = Cow.prototype;
</pre>
<p>Теперь <code>fred</code> наследуется непосредственно от <code>Cow.prototype</code>, а не от <code>Employee.prototype</code>, и теряет свойства, изначально унаследованные от <code>Employee.prototype</code>.</p>
<p>Однако, это применяется только к {{jsxref("Object.isExtensible()", "расширяемым", "", 1)}} объектам, у нерасширяемых объектов свойство <code>__proto__</code> не может быть изменено:</p>
<pre class="brush: js">var obj = {};
Object.preventExtensions(obj);
obj.__proto__ = {}; // выкинет TypeError
</pre>
<p>Обратите внимание, что свойство <code>__proto__</code> может быть переопределено даже у объекта <code>Object.prototype</code>, если новая цепочка заканчивается {{jsxref("Global_Objects/null", "null")}}:</p>
<pre class="brush: js">var b = {};
Object.prototype.__proto__ =
Object.create(null, // [[Prototype]]
{ hi: { value: function() { alert('hi'); } } });
b.hi();
</pre>
<p>Если свойство <code>__proto__</code> объекта {{jsxref("Object.prototype")}} не установлено в {{jsxref("Global_Objects/null", "null")}}, или в другой объект, чья цепочка прототипов, в конечном итоге, явно не заканчивается значением {{jsxref("Global_Objects/null", "null")}}, будет выкинуто исключение {{jsxref("Global_Objects/TypeError", "TypeError")}} «циклическое значение __proto__», поскольку цепочка должна заканчиваться {{jsxref("Global_Objects/null", "null")}} (как это и происходит на {{jsxref("Object.prototype")}} при нормальных обстоятельствах).</p>
<h2 id="Specifications">Спецификации</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Спецификация</th>
<th scope="col">Статус</th>
<th scope="col">Комментарии</th>
</tr>
<tr>
<td>{{SpecName('ES6', '#sec-additional-properties-of-the-object.prototype-object', 'Object.prototype.__proto__')}}</td>
<td>{{Spec2('ES6')}}</td>
<td>Включён в (нормативное) приложение для дополнительных возможностей ECMAScript для веб-браузеров (обратите внимание, что спецификация закрепляет то, что уже реализовано).</td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility">Совместимость с браузерами</h2>
<div class="note">
<p><strong>Примечание:</strong> спецификация ES6 требует поддержку свойства <code>__proto__</code> только в браузерах и не требует его поддержку в других окружениях (хотя оно и рекомендуется в качестве обязательного). Если ваш код должен работать в не-браузерных окружениях, вместо свойства рекомендуется использовать методы {{jsxref("Object.getPrototypeOf()")}} и {{jsxref("Object.setPrototypeOf()")}}.</p>
</div>
<div>{{Compat("javascript.builtins.Object.proto")}}</div>
<h2 id="See_also">Смотрите также</h2>
<ul>
<li>{{jsxref("Object.prototype.isPrototypeOf()")}}</li>
<li>{{jsxref("Object.getPrototypeOf()")}}</li>
<li>{{jsxref("Object.setPrototypeOf()")}}</li>
</ul>
|