Object.prototype.__proto__
Ostrzeżenie: Zmiana [[Prototype]]
obiektu, ze względu na sposób w jaki współczesny JavaScript optymalizuje dostęp do właściwości, jest bardzo powolną operacją (W każdej przeglądarce!). Efekty modyfikacji łańcucha dziedziczenia są rozległe, nie chodzi tu tylko o wydłużenie czasu potrzebnego na wykonanie operacji obj.__proto__ = ...
, skutki wpływają na każdy fragment kodu który odwołuje się do jakiejkolwiek właściwości obiektu, którego [[Prototype]]
został zmieniony. Dlatego jeżeli zależy ci na wydajności powinieneś unikać tej operacji. Zamiast tego, stwórz nowy obiekt z porządanym [[Prototype]]
za pomocą Object.create()
(en-US).
Ostrzeżenie: Mimo że w dzisiejszych czasach Object.prototype.__proto__
jest wspierany w niemal każdej przeglądarce, jego istnienie oraz zachowanie zostały ujednolicone w specyfikacji ECMAScript 2015 jedynie jako legacy feature aby zapewnić kompatybilność z przeglądarkami. Dla lepszego wsparcia rekomenduje się używanie Object.getPrototypeOf()
(en-US).
Właściwość __proto__
obiektu Object.prototype
(en-US) jest operatorem dostępu (metoda getter i setter) która operuje na wewnętrznym [[Prototype]]
(na obiekcie lub na null
) obiektu do którego się odnosi.
Użycie __proto__
jest kontrowersyjne i podchodzi się do niego z niechęcią. Oryginalnie nigdy nie pojawiło się w specyfikacji EcmaScript, ale nowoczesne przeglądarki postanowiły mimo wszystko to zaimplementować. Dopiero niedawno właściwość __proto__
znalazła swoje miejsce w specyfikacji ECMAScript 2015 aby zapewnić kompatybilność z tymi przeglądarkami. Jest ona jednak przestarzała ze względu na Object.getPrototypeOf
(en-US)/Reflect.getPrototypeOf
(en-US) oraz Object.setPrototypeOf
(en-US)/Reflect.setPrototypeOf
(en-US) (choć modyfikowanie [[Prototype]]
wciąż jest operacją powolną, która powinna być unikana przez wzgląd na wydajność).
Właściwość __proto__
może być również używana w notacji literałowej aby ustawić [[Prototype]]
tworzonego obiektu, jako alterantywa do Object.create()
(en-US). Zobacz: inicjalizator obiektu / notacja literałowa.
Składnia
var Kolo = function () {};
var ksztalt = {};
var kolo = new Kolo();
// Ustawianie prototypu obiektu
// ZDEPRECJONOWANE. Używamy tego tylko dla przykładu. NIE RÓB TEGO w prawdziwym kodzie.
ksztalt.__proto__ = kolo;
// Sprawdzenie prototypu obiektu
console.log(ksztalt.__proto__ === kolo); // true
var ksztalt = function () {};
var p =
{
a: function ()
{
console.log('aaa');
}
};
ksztalt.prototype.__proto__ = p;
var kolo = new ksztalt();
kolo.a(); // aaa
console.log(ksztalt.prototype === kolo.__proto__); // true
// albo
var ksztalt = function () {};
var p =
{
a: function ()
{
console.log('aaa');
}
};
var kolo = new ksztalt();
kolo.__proto__ = p;
circle.a(); // aaa
console.log(ksztalt.prototype === kolo.__proto__); // false
// albo
function ksztalt() {};
ksztalt.prototype.a = function ()
{
console.log('aaa');
}
var kolo = new ksztalt();
kolo.a(); // aaa
console.log(kolo.__proto__ === ksztalt.prototype); // true
// albo
var ksztalt = function () {};
ksztalt.prototype.a = function ()
{
console.log('aaa');
}
var kolo =
{
__proto__: ksztalt.prototype
};
kolo.a(); // aaa
console.log(kolo.__proto__ === ksztalt.prototype); // true
Uwaga: __proto__
zapisujemy jako dwie podłogi, następnie pięć liter "proto", następnie dwie kolejne podłogi.
Opis
Metoda getter właściwości __proto__
daje nam dostęp do wewnętrznej wartości [[Prototype]]
obiektu. Dla obiektów stworzonych przy użyciu literału jest to Object.prototype
(en-US). Dla tablic stworzonych przy użyciu literału jest to Array.prototype
. Dla funkcji ta wartość to Function.prototype
(en-US). Dla obiektów stworzonych przy użyciu new Funkcja
, gdzie Funkcja
to jeden z wbudowanych konstruktorów dostarczanych przez JavaScript (Array
, Boolean
, Date
, Number
, Object
, String
, i tak dalej — wliczając nowe konstrukotry, które mogą zostać dodane w przyszłości), ta wartość to zawsze Funkcja.prototype
. Dla obiektów stworzonych przy użyciu new Funkcja
, gdzie Funkcja
to funkcja zdefiniowana w kodzie, wartość ta przyjmuje taką samą wartość jak Funkcja.prototype
.
Metoda setter właściwości __proto__
umożliwia modyfikowanie [[Prototype]]
obiektu. W tym celu obiekt musi być roszerzalny według funkcji Object.isExtensible()
(en-US), jeżeli nie jest TypeError
(en-US) zostanie wyrzucony. Dostarczana wartość musi być obiektem albo typem null
. Podanie jakiejkolwiek innej wartości nie zrobi nic.
Aby zrozumieć w jaki sposób prototypy używane są do dziedziczenia, zobacz artykuł o dziedziczeniu oraz łańcuchu prototypów.
Właściwość __proto__
jest prostym operatorem pamięci na Object.prototype
(en-US) składającym się z metody getter i setter. Dostęp do właściwości __proto__
który ostatecznie konsultuje się z Object.prototype
(en-US) znajdzie tę właściwość, ale dostęp który nie konsultuje Object.prototype
(en-US) nie znajdzie jej. Jeżeli jakaś inna właściwość __proto__
zostanie znaleziona, zanim Object.prototype
(en-US) zostanie skonsultowany, to właściwość ta przesłoni tą znalezioną w Object.prototype
(en-US).
Specyfikacje
Specification | Status | Comment |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'Object.prototype.__proto__' in that specification. |
Standard | Dołączony (normatywnie) jako jeden z dodatkowych ECMAScript legacy features dla przeglądarek (zauważ że specyfikacja jedynie ujednoliciła coś, co było już zaimplementowane w przeglądarkach). |
ECMAScript (ECMA-262) The definition of 'Object.prototype.__proto__' in that specification. |
Living Standard |
Kompatybilność z przeglądarką
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Basic support | (Yes) | (Yes) | 11 | (Yes) | (Yes) |
Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Basic support | (Yes) | (Yes) | (Yes) | (Yes) | (Yes) | (Yes) |
Uwagi odnośnie kompatybilności
Mimo, że specyfikacja ECMAScript 2015 określa iż wsparcie dla __proto__
jest wymagane tylko dla przeglądarek internetowych (w zasadzie normatywnie), to inne środowiska równieź mogą wspierać tę funkcjonalność.