Chapter 8: Prototypes, inheritance
8.1 Prototypal inheritance
[[Prototype]]
Objects have a special hidden property [[Prototype]]
(as named in the specification), that is either null or references another object (prototype).
When we want to read a property from object, and it’s missing, JavaScript automatically takes it from the prototype, which is called “prototypal inheritance”.
To set the internal property, use the special name __proto__
. (getter/setter for [[Prototype]]
)
The references can’t go in circles. Other types of __proto__
are ignored.
Writing doesn’t use prototype
The prototype is only used for reading properties. Write/delete operations work directly with the object. (Accessor properties are an exception.)
The value of “this”
No matter where the method is found: in an object or its prototype. In a method call, this
is always the object before the dot. Methods are shared, but the object state is not.
for…in loop
The for..in
loop iterates over inherited properties. It only lists enumerable properties.
obj.hasOwnProperty(key)
returns true
if obj
has its own (not inherited) property named key
. This method is stored in the Object.prototype
object and all of its methods are not enumerable.
8.2 F.prototype
If F.prototype
is an object, then the new
operator uses it to set [[Prototype]]
for the new object. Change to this property won't affect the existing objects created by the constructor.
Default F.prototype, constructor property
The default prototype
is an object with the only property constructor
that points back to the function itself. We can use constructor
property to create a new object with the same constructor.
JavaScript itself does not ensure the right constructor
value. To keep the right constructor
, we can choose to add/remove properties to the default prototype
instead of overwriting it as a whole.
8.3 Native prototypes
Object.prototype
The string [object Object]
is generated by the Object.prototype.toString()
method. There is no more [[Prototype]]
in the chain above Object.prototype
.
Other built-in prototypes
Other built-in objects such as Array
, Date
, Function
and others also keep methods in prototypes. Methods of thee built-ins also reside in the prototypes of their object wrappers.
Changing native prototypes
Prototypes are global, so it’s easy to get a conflict. There is only one case where modifying native prototypes is approved: polyfilling.
Borrowing from prototypes
The internal algorithm of the built-in join
method only cares about the correct indexes and the length
property. It doesn’t check if the object is indeed an array.
This can also be done by chaning the __proto__
property of the obj
, but remember that we only can inherit from one object at a time.
8.4 Prototype methods, objects without proto
Object.create(proto, [descriptors])
– creates an empty object with given proto as[[Prototype]]
and optional property descriptors.Object.getPrototypeOf(obj)
– returns the[[Prototype]]
of obj.Object.setPrototypeOf(obj, proto)
– sets the[[Prototype]]
of obj to proto.
These should be used instead of __proto__
.
The descriptors are in the same format as the Property flags and descriptors.
This call makes a truly exact copy of obj
, including all properties: enumerable, non-enumerable, data properties, setters/getters, and the right [[Prototype]]
.
"Very plain" objects
The __proto__
property is special: it must be either an object or null
. When the object is used as associative arrays to store key/value pairs, it will cause error if the user assign an object to the __proto__
key.
__proto__
is a getter/setter inherited from its prototype, so we can create a plain object by setting its prototype to null
:
Last updated