This page was translated from English by the community.Learn more and join the MDN Web Docs community.
Object.prototype.__proto__
Предупреждение:Изменение прототипа[[Prototype]] объекта является, по самой природе оптимизации доступа к свойствам в современных движках JavaScript, очень медленной операцией, это справедливо длялюбого браузера и движка JavaScript. Изменение прототипов очень тонко и обширно влияет на производительность, причём это влияние не ограничивается просто временем для операции присваиванияobj.__proto__ = ..., оно может распространяться налюбой код, который имеет доступ клюбому объекту, чей прототип[[Prototype]] был изменён. Если вы заботитесь о производительности, вы никогда не должны изменять прототип[[Prototype]] объекта. Вместо этого создайте объект с нужным прототипом[[Prototype]], с помощью методаObject.create().
Предупреждение:Хотя на сегодняшний момент большинство браузеров поддерживают свойствоObject.prototype.__proto__, его поведение только недавно было стандартизировано в новой спецификации ECMAScript 6. Если вам требуется поддержка браузеров до этой спецификации, рекомендуется использовать вместо него методObject.getPrototypeOf().
In this article
Сводка
Свойство__proto__ объектаObject.prototype является свойством доступа (комбинацией геттера и сеттера), которое расширяет внутренний прототип[[Prototype]] объекта (являющийся объектом илиnull), через который осуществлялся доступ.
Использование свойства__proto__ вызывает споры и многих оно разочаровало. Ранее оно никогда не включалось в спецификацию EcmaScript, но современные браузеры всё равно решили его реализовать. Сегодня свойство__proto__ стандартизировано в спецификации ECMAScript 6 и будет поддерживаться в будущем. Тем не менее, изменение прототипа[[Prototype]] объекта всё ещё остаётся медленной операцией, которую следует избегать, если вы беспокоитесь о производительности.
Свойство__proto__ также может использоваться при определении литерала объекта, устанавливая прототип[[Prototype]] объекта при его создании. Этот способ может рассматриваться как альтернатива методуObject.create(). Смотрите такжелитеральный синтаксис инициализации объекта.
Синтаксис
var shape = {}, circle = new Circle();// Установка прототипа объектаshape.__proto__ = circle;// Получение прототипа объектаconsole.log(shape.__proto__ === circle); // trueОбратите внимание: название свойства состоит из двух подчёркиваний, следующих за ними пяти символов «proto» и следующих за ними ещё двух подчёркиваний.
Описание
Геттер свойства__proto__ расширяет значение внутреннего прототипа[[Prototype]] объекта. Для объектов, созданных с использованием литеральной формы создания объекта, это значение равноObject.prototype. Для функций это значение равноFunction.prototype. Для объектов, созданных с использованием формы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 — свойством, состоящим из геттера и сеттера. Свойство__proto__ будет найдено, если, в конечном итоге, его поиск пройдёт черезObject.prototype, но при доступе к нему не черезObject.prototype, оно найдено не будет. Если перед просмотромObject.prototype буден найдено какое-нибудь другое свойство__proto__, оно скроет искомое свойствоObject.prototype.
var noProto = Object.create(null);console.log(typeof noProto.__proto__); // undefinedconsole.log(Object.getPrototypeOf(noProto)); // nullnoProto.__proto__ = 17;console.log(noProto.__proto__); // 17console.log(Object.getPrototypeOf(noProto)); // nullvar protoHidden = {};Object.defineProperty(protoHidden, "__proto__", { value: 42, writable: true, configurable: true, enumerable: true,});console.log(protoHidden.__proto__); // 42console.log(Object.getPrototypeOf(protoHidden) === Object.prototype); // trueПримеры
В следующем примере создаётся новый экземплярEmployee, а затем проверяется, что его свойство__proto__ является тем же самым объектом, что и его конструкторprototype.
// Декларируем функцию, используемую как конструкторfunction Employee() { /* инициализируем экземпляр */}// Создаём новый экземпляр Employeevar fred = new Employee();// Проверка на эквивалентностьfred.__proto__ === Employee.prototype; // trueВ этот моментfred унаследован отEmployee, однако присваивание другого объекта вfred.__proto__ может изменить это:
function Cow() { /* инициализируем экземпляр */}// Присваиваем __proto__ новый объектfred.__proto__ = Cow.prototype;Теперьfred наследуется непосредственно отCow.prototype, а не отEmployee.prototype, и теряет свойства, изначально унаследованные отEmployee.prototype.
Однако, это применяется только красширяемым объектам, у нерасширяемых объектов свойство__proto__ не может быть изменено:
var obj = {};Object.preventExtensions(obj);obj.__proto__ = {}; // выкинет TypeErrorОбратите внимание, что свойство__proto__ может быть переопределено даже у объектаObject.prototype, если новая цепочка заканчиваетсяnull:
var b = {};Object.prototype.__proto__ = Object.create( null, // [[Prototype]] { hi: { value: function () { alert("hi"); }, }, },);b.hi();Если свойство__proto__ объектаObject.prototype не установлено вnull, или в другой объект, чья цепочка прототипов, в конечном итоге, явно не заканчивается значениемnull, будет выкинуто исключениеTypeError «циклическое значение __proto__», поскольку цепочка должна заканчиватьсяnull (как это и происходит наObject.prototype при нормальных обстоятельствах).
Спецификации
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-object.prototype.__proto__> |
Совместимость с браузерами
Loading…
Примечание:Спецификация ES6 требует поддержку свойства__proto__ только в браузерах и не требует его поддержку в других окружениях (хотя оно и рекомендуется в качестве обязательного). Если ваш код должен работать в не-браузерных окружениях, вместо свойства рекомендуется использовать методыObject.getPrototypeOf() иObject.setPrototypeOf().