Prototype chains and classes
JavaScript introduces OOP(Object Oriented Programming) in four main ways.
Single Object
Prototype chain
Classes
Subclasses
Now let take a look at each of them and how they work.
Single Object
Single object are the basic building block of OOP in JavaScript.
Object in JavaScript are:
A set of properties(key-value pairs)
A property can only be a string or symbol
Object play two roles:
Records - Objects as records have a fixed number of properties, the keys of these property are known at development time. It does not matter if the values are of different types. Property keys are of type string and symbol under the hood.
Dictionaries - Object as dictionaries do have a variable number of properties, and the keys are not known at development time. All of their values are also of the same type. Maps are usually better dictionaries then object.
Object as Records
objects literals are used to create object as record. They area stand out feature of JavaScript; you can directly create object no need for classes.
Here is an example of how to create object literals
const jane = {
first:'John'
last:'Doe'
}
In this example we created an object via object literals . It started with { and ended with }.
The first property has a key a of 'first' and 'John' is the value
The second property has a key of 'last' and 'Doe' is the value
Note whenever the value of a property is defined via variable name and that name is the same as the key. You can remove the key.
Now let take a look at how to get and set properties of an object
const obj = {
firstName:'John',
lastName:'Doe'
}
// To get the property firstName
const first = obj.firstName
console.log(first) // 'John'
// To set the property firstName
obj.firstName = 'Jack'
console.log(obj.firstName) // 'Jack'
If we set an unknown property, we create a new entry in the object literal.
// An empty object
const obj = {}
obj.fullName = 'John Doe'
console.log(obj) // {fullName:'John Doe'}
Object Literals: Accessors
let discuss the two kinds of accessors in javaScript.
A getter is a method entity that is invoked when getting a property
A setter is a method entity that is invoked by setting a property.
A getters
A getter is created by prefixing a method definition with the modifier get;
const dan = {
first:'Dan',
last:'Lok',
get fullName(){
return `$(this.first) ${this.last}`;
}
}
console.log(dan.fullName) // Dan Lok
A setter
A setter is created by prefixing a method definition with the modifier set
const dan = {
first:'Dan',
last:'Lok',
set fullName(fullName){
const parts = fullName.split(' ')
this.first = parts[0]
this.last = parts[1]
}
}
dan.fullName = 'John Doe'
console.log(dan.fullName) // 'John Doe'
Methods
Methods are properties of an object whose values are function.
const dan ={
first:'Dan',
calls(text){
return `${this.first} calls ${this.text}`
}
}
// methods are function
typeof dan.call // function
Object as Dictionaries
Object are more suitable as records, it's right to say they work best as records. Before maps was introduced as a data structure in ECMAScript 6, JavaScript did not have a data structure for dictionaries like some languages do. e.g. python etc. Object had to be used as dictionaries, using object as dictionary had it own challenges since keys had to be strings.
In object as records property keys were fixed tokens that had to be valid identifiers and internally became string.
const obj = {
myIdentifier:'hello'
}
// get property
obj.myIdentifier // 'hello'
// set property
obj.myIdentifier = 123
obj.myIdentifier // 123
Now let see how we can use arbitrary fixed string as keys
When creating property keys via object literals, we can quote property keys with single or double quotes
const obj ={
'this is a string': 123
}
// When getting or setting them we can use square with strings inside.
// Getting a property
obj['this is a string'] // 123
// Setting a property
obj['this is a string0'] = 'hello'
obj['this is a string'] // 'hello'
This way of naming properties can also be applied to methods
const obj = {
'this is a method'(){
return 'successfull'
}
// Getting the method
obj['this is a method']() // 'successfull'
Prototype chain
In JavaScript Prototype are the only inheritance mechanism. Every Object has a prototype that is either null or an object
There is a special property that you can use to set the prototype, that is the __proto__;
const proto = {
prototype:'a'
}
const obj = {
__proto__:proto,
myProp:'abc'
}
From the above example we can see obj inherits .prototype. A prototype object can have a prototype itself. That's how come we have the name prototype chain. With inheritance you might think we are dealing with single object, but in fact we are dealing with chain of objects.
Properties that are not inherited are called own properties. In the diagram above obj has one own property that is objProp.
Working with prototypes.
Pseudo-property __proto__ should be avoided. Through getters and setters we can implement __proto__ using a class object. Let take a look at the example
class Object {
get __proto__(){
return Object.getPrototypeOf(this);
}
set __proto__(){
Object.setProtypeOf(this, other);
}
}
With these we can turn __proto__ off by creating an object that doesn't have object.prototype in its prototype chain.
Note that __proto__ in object literals is an in-built feature and its always available.