Prototypes

We've already discovered there are two types of data in JavaScript:

  • Primitives
  • Objects

You can view a value's prototype by accessing the .prototype property

Let's start by finding out what data types have prototypes

index.js
1
constname='Marilyn';
2
3
console.log(typeofname);
4
//string
5
6
console.log(typeofname.prototype);
7
//undefined
8
9
constage=21;
10
11
console.log(typeofage);
12
//number
13
14
console.log(typeofage.prototype);
15
//undefined
16
17
constisAlive=true;
18
19
console.log(typeofisAlive);
20
//boolean
21
22
console.log(typeofisAlive.prototype);
23
//undefined
24
25
constnullValue=null;
26
27
console.log(typeofnullValue);
28
//object
29
30
console.log(typeofnullValue.prototype);
31
//TypeError:Cannotreadproperty'prototype'ofnull
32
33
constunknown=undefined;
34
35
console.log(typeofunknown);
36
//undefined
37
38
console.log(typeofunknown.prototype);
39
//TypeError:Cannotreadproperty'prototype'ofundefined
40

So far we've found out that primitive data types do not have prototypes.

Object Prototypes

Arrays

index.js
1
constshoppingList=['hummus','avocado','batteries'];
2
3
console.log(typeofshoppingList);
4
//object
5
6
console.log(typeofshoppingList.prototype);
7

We can see from above that arrays don't have prototypes

Plain objects

index.js
1
constobectOfMyAffection={
2
name:'Anonymous',
3
address:'Neveryoumind'
4
}
5
6
console.log(typeofobectOfMyAffection);
7
//object
8
9
console.log(typeofobectOfMyAffection.prototype);
10
//undefined
11

We can see from above that plain objects do not have prototypes

Functions

index.js
1
//functiondeclaration
2
constmakeMe=function(){
3
console.log('makeme');
4
}
5
6
console.log(typeofmakeMe);
7
//function
8
9
console.log(typeofmakeMe.prototype);
10
//object
11
12
//arrowfunction
13
constdareMe=()=>{
14
console.log('dareme');
15
}
16
17
console.log(typeofdareMe);
18
//function
19
20
console.log(typeofdareMe.prototype);
21
//undefined
22

Function declarations have prototypes but arrow functions do not.

Classes

index.js
1
classClassyPerson{
2
}
3
4
console.log(typeofClassyPerson);
5
//function
6
7
console.log(typeofClassyPerson.prototype);
8
//object
9
10
constnewClassyPerson=newClassyPerson();
11
12
console.log(typeofnewClassyPerson);
13
//object
14
15
console.log(typeofnewClassyPerson.prototype);
16
//undefined
17
  • classes are functions which create objects. This is confirmed on line 5, we see that ClassyPerson is a function. The class keyword is syntax sugar for a function declaration.
  • Functions inherit from the object prototype. We will cover what this means below.
  • Classes return plain objects.
  • Plain objects do not have prototypes, hence why the new instance of ClassyPerson (newClassyPerson) has no prototype.

What we have learned here is that of the object data type, only function declarations, classes (not instances of a class) have prototypes

Inheritance

Inheritance is a way for different object to share the same code. That code can be keys, values or methods.

Constructor Functions

A constructor function is a function which you can call, to create new objects.

They should always be capatalised. This is how we differentiate them from regular functions.

Example of a constructor function:

index.js
1
functionCar(make='defaultmake',model='defaultmodel'){
2
this.make=make;
3
this.model=model;
4
}
5
6
constcustomCar=newCar('custommake','custommodel');
7
8
console.log(customCar.make,customCar.model);
9
//custommakecustommodel
10
11
Car.prototype.drive=function(){
12
console.log('vroom!');
13
}
14
15
console.log(Car.prototype.hasOwnProperty('drive'));
16
//true
17
18
console.log(customCar.prototype.hasOwnProperty('drive'));
19
//TypeError:Cannotreadproperty'hasOwnProperty'ofundefined
20
21
console.log(Car.hasOwnProperty('drive'));
22
//false
23
24
console.log(customCar.hasOwnProperty('drive'));
25
//false
26
27
28
Car.prototype.drive();
29
//vroom!
30
31
customCar.drive();
32
//vroom!
33
34
/*SETTINGAPROTOTYPE*/
35
customCar.__proto__=Car;
36
console.log(customCar.prototype.hasOwnProperty('drive'));
37
//true
38

We are seeing prototypal inheritance at play here.

When a new instance of an object is created, if you try to call a method on that instance, in the following order this will happen:

  • It will try to search for the method on the instance itself
  • If it is not available on the instance, it will search on the instance's parent's prototype. On line 17, we see that drive is not available on the instance.
  • A link is created from the parent prototype to the instance, which gives the instance access to all the methods and properties of the parent's prototype. This is why the method call on line 24 works - drive is a reference to customCar's parent's prototype, which customCar has a link to. This is what is meant by prototypal inheritance, it is actually a "delegation", not an inheritance in the real sense.
  • If we want to explicitly set an instance's prototype, we can do so with .__proto__

Summary:

  • Primitive data types, plain object, arrow functions do not have prototypes
  • Of objects, only function declarations and classes (not instances of a class) have prototypes. classes are syntax sugar for function declarations.

Further reading

https://hackernoon.com/understanding-javascript-prototype-and-inheritance-d55a9a23bde2