OOP
There are 3 ways of using objects:
- Object Literals
- Constructor Functions
- Classes
Object Literals
let person = {}
is the same as let person = new Object()
.
Listing members
Equality
For objects, the reference is compared.
==
Not type-safe.
===
Type-safe.
NaN != NaN
+0 == -0
Object.is(obj1, obj2)
NaN == NaN.
+0 != -0
Constructor Functions
Object.create()
Both object literals and constructor functions use Object.create()
underneath.
It’s called “pure prototypal inheritance”.
It’s not used often, the other ways are prefered. The above is the same as:
Another usage:
This creates an empty jack
object and sets person
as its prototype. The
default values stay on prototype, jack
can set its own values for them:
Merging Objects
Object Properties
Property Descriptor
Every property fo an object has a descriptor:
It returns an object:
Writable
We can modify the descriptor:
Now, the property becomes read only and if we try to change it we get an error:
TypeError: Cannot assign to read only property ‘firstName’ of object ‘Object’
However, if firstName
was an object, it would be still possible to change its
properties (but not firstName
itself).
To completely “lock” and object, it needs to be frozen:
Enumerable
Controls whether object can be enumerated with for...in
loop or Object.keys
.
We can disable enumeration for some proeprty:
Now, firstName
will not show up in results of enumeration. It also affects
JSON serialization with JSON.stringify(person)
. The firstName
property will
not be serialized.
Configurable
It controls whether:
- the property descriptor’s
enumerable
andconfigurable
cannot be changed - the property can be deleted from the object or not
Once it’s done, it cannot be changed back! Only writable
stays changeable.
Getters and Setters
Prototypes
- it is an object that exists on every function (
{}
). When a function is created, there is an Object created in memory, with the same name as the function. This object is a prototype of the function. - “normal” objects do have a prototype, but they do not have
protoype
property (undefined
). It is available atperson.__proto__
(Object {}
) - prototype has a
constructor
property that points to a function that created it
Function’s prototype is an Object instance that is given as a prototype object
for every object created from that function as a constructor. This object
instance contains the methods such as bind
, call
, apply
. This is how
functions inherit these methods.
Object’s prototype is the same object that the constructor function had (they refer to the same object in memory).
Example:
age
property exists on Person
’s prototype. When we create some object from
that constructor function, it will have the same prototype (same object
reference).
When we request age
on jim
, JS:
- looks under
jim
- there is noage
- looks under
jim.__proto__
- there isage
and it is used
When we change the value of jim.age
only this is changed. The prototype’s
value does not change.
We added the getFullName
on the prototype, and not in the constructor
directly, because this way the function is created just once in memory. If we
were creating it in the constructor every instance of Person
would have a
separate object for this method!
There is a Prototype Chain. Every objech has prototype. If some property/method is not found on an object, JS engine looks into the prototype of that object. If it’s not there either, it looks into prototype’s prototype, and so on.
The same behaviour is for methods. We can even add more stuff to the prototype after the objects that use this prototype have been created. These objects will get the new functionality!
hasOwnProperty
Inheritance
All objects in JS inherit from Object
and Object
has no prototype (null
).
The 3 things are really the key in defining inheritance:
- calling base function in a constructor of a new type
- creating a new prototype based on base’s prototype
- setting the prorotype’s constructor back to the correct one
Static members
Classes
It is just syntactic sugar for the previous approach. Classes in JS are objects!
Getters and setters are set as enumerable: false
by default. To change that a
property descriptor needs to be modified. Getters and setters are defined on
prototype, while other properties and methods are defined on the instances
directly.
Now, fullName
is enumerable.
Inheritance
Under the hood, it just sets Person
as a prototype (__proto__
) of Student
.
Static members
static
keyword is for defining static members.