09. Prototype Chain
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__
на другой объект, то при чтении свойства из него, если свойство отсутствует в самом объекте, оно ищется в объекте __proto__
.
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
ifobj
is not an object.Object.setPrototypeOf(obj, prototype)
- method sets the prototype of a specified object to another object ornull
.
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.
The __proto__
property may not be supported. A simple check for the getter/setter:
Recommendations:
Use
Object.getPrototypeOf()
to get the prototype of an object.Prefer
Object.create()
to create a new object with a given prototype. AvoidObject.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
super
В ES2015 появилось новое ключевое слово super
, предназначенное только для использования в методах объекта. Вызов super.parentProperty
позволяет из метода объекта получить свойство его прототипа:
Свойство super
работает через прототип только в методах объекта. При обращении через super
используется [[HomeObject]]
текущего метода, и от него берётся __proto__
. В частности, если переписать этот код, оформив rabbit.walk
как обычное свойство-функцию, то будет ошибка. Исключением из этого правила являются функции-стрелки. В них используется super
внешней функции. Например, здесь функция-стрелка в setTimeout
берёт внешний super
:
Check prototype chain with obj.isPrototypeOf()
obj.isPrototypeOf()
The proto.isPrototypeOf(obj)
method checks if an proto
exists in obj
object's prototype chain.
Access to properties
Доступ к любым свойствам объекта выполняется в контексте (наследования) цепочки прототипов.
Предположим, что программа обращается к свойству
x
объектаo
. Если объектo
не имеет собственного свойства с таким именем, выполняется попытка отыскать свойствоx
в прототипе объектаo
. Если объект-прототип не имеет собственного свойства с этим именем, но имеет свой прототип, выполняется попытка отыскать свойство в прототипе прототипа. Так продолжается до тех пор, пока не будет найдено свойствоx
или пока не будет достигнут объект, не имеющий прототипа.
В цепочке прототипов, свойство объекта с определенным именем перекрывает свойство с таким же именем в его цепочке прототипов, если перекрытие не запрещено.
При присваивании свойства всегда меняется текущий объект и никогда прототип. Присваивание свойства может не выполниться в некоторых случаях.
Операция присваивания значения свойству проверит наличие этого свойства в цепочке прототипов, чтобы убедиться в допустимости присваивания. Например, если объект o
наследует свойство x
, доступное только для чтения, то присваивание выполняться не будет. Однако если присваивание допустимо, всегда создается или изменяется свойство в оригинальном объекте и никогда в цепочке прототипов.
Тот факт, что механизм наследования действует при чтении свойств, но не действует при записи новых значений, является ключевой особенностью языка JavaScript, потому что она позволяет выборочно переопределять унаследованные свойства.
Существует одно исключение из этого правила, когда операция присваивания значения свойству терпит неудачу. Если объект o
наследует свойство x
и доступ к этому свойству осуществляется посредством методов доступа, то вместо создания нового свойства x
в объекте o производится вызов метода записи нового значения. Однако обратите внимание, что метод записи вызывается относительно объекта o
, а не относительно прототипа, в котором определено это свойство, поэтому, если метод записи определяет какие-либо свойства, они будут созданы в объекте o
, а цепочка прототипов опять останется неизменной.
Dictionaries
Объекты без прототипа часто называются картами или dictionary pattern:
Преимущество таких объектов в том, что они концептуально более проще, чем объекты, использующиеся как карты. Для них можно безопасно использовать все операторы над объектами, без различных проверок, связанных с цепочкой прототипов.
Last updated
Was this helpful?