Category: Development

Prototypal inheritance

Author(s)

Iris
Iris
Prototypal is a complicated term for a very powerful concept. It comes from the word prototype, which means an original model on which something is patterned (Merriam Webster dictionnary).
In our case, it means constructing an original object, defining its characteristics and its functions, which will then serves as pattern for new objects.
In JavaScript, we can access the prototype of any object thanks to a hidden property [[Prototype]]. It refers to either an object or null.

How does it work ?

To access an object prototype, we can use __proto__ which is the historical getter/setter for [[Prototype]]. Let's make a concrete example:
let userPrototype = {
  isAdmin: true,
};

let user = {
  username: 'Jane Smith',
};

user.__proto__ = userPrototype;
console.log(user); 
/* the <span style="font-size: inherit;">[[Prototype]]</span> hidden property is set to userPrototype
{
  username: 'Jane Smith',
  [[Prototype]]: Object {
    isAdmin: true,
  }
}
*/
console.log(user.isAdmin); // <em>true</em>
console.log(user.username); // <em>Jane Smith</em>
We can now access the property isAdmin directly from the user object, because we have set its prototype to userPrototype.
Let's say now that our user does not have admin right. I can modify it directly:
user.isAdmin = false;
console.log(user.isAdmin); // <em>false</em>
console.log(userPrototype.isAdmin); // <em>true</em>
This modifies only the isAdmin property for the user object, but the prototype userPrototype remains unchanged, with isAdmin set to true.

Inheritance

Prototypal inheritance means we can access any properties or methods from another object. Each object inherits from a prototype, which itself inherits from another prototype and so on, until [[Prototype]] equals null. This is called prototype chaining.
This means when trying to access an object properties, the code search will go through each chained elements until it finds either the property or null is reached.

Everything is prototypal

All JavaScript objects inherit properties and methods from a prototype:
  • Date objects inherit from Date.prototype.
  • Array objects inherit from Array.prototype.
  • Player objects inherit from Player.prototype.
This is how we have access to a bunch of methods depending on the type of object: toUppercase(), split(), format(), etc.

How powerful it can be

Why is prototyping so powerful ? Let's imagine we have the following code:
let userPrototype = {
  username: '',
  greetings: function() {
    console.log(`Hello ${this.username}`);
  },
};

let user = {
  username: 'Jane Smith',
};

user.__proto__ = userPrototype;
console.log(user.greetings()); // <em>Hello Jane Smith</em>
Now let's say that my greeting function is no longer what I want. Instead I would d like to ask how the user is doing. By modifying the method in the prototype, it will automatically applies to the children who inherits from it:
userPrototype.greetings = function() {
  console.log(`Hello ${this.username}, how are you doing ?`);
};
console.log(user.greetings()); // <em>Hello Jane Smith, how are you doing ?</em>

Constructor

Just like for object-oriented programming, all JavaScript objects have a constructor, even when it is not explicitly created. The following examples demonstrates this point:
let object1 = {};
let object2 = new Object;
console.log(object1.constructor); // <em>Object</em>
console.log(object2.constructor); // <em>Object</em>

let date = new Date;
console.log(date.constructor); // <em>Date</em>

let array1 = [];
let array2 = new Array;
console.log(array1.constructor); // <em>Array</em>
console.log(array2.constructor); // <em>Array</em>
We saw that using prototypal inheritance can prevent code duplication, since we can inherit properties and methods from a prototype. It also makes sure that if a prototypal method is modified, it will be the case as well for all the children that inherits from it.
But so far, the way to set the prototype of an object (user.__proto__ = userPrototype) is not great if we have to create a bunch of new users each inheriting from userPrototype.
By using the constructor function, we can improve this: it will automatically set the [[Prototype]] property for us.
function UserPrototype(username) {
  this.username = username;
};
UserPrototype.prototype.greetings = function () {
  console.log(`Hello ${this.username}`);
};


const user = new UserPrototype('Jane Smith');
console.log(user.greetings()); // <em>Hello Jane Smith</em>
console.log(user.constructor); // <em>UserPrototype</em>
From this point, we can then use Class which is just a sugar coat to prototyping in JavaScript:
class UserPrototype {
    constructor (username) {
        this.username = username
    };

    greetings = () => console.log(`Hello ${this.username}`);
}

To wrap up

Advantages

JavaScript, at its core, is prototypal. It means we can define the properties and methods of a prototype and then create objects which will inherit from it. This makes it very similar to Object-Oriented programming and has big advantages:
1. It prevents duplication of logic and data: objects can share properties and methods thanks to inheritance.
2. It uses less memory. Let's create the following code
function User() {
  this.greetings = function() {};
}

const John = new User();
const Jane = new User();
(John.greetings === Jane.greetings); // false

1 function = 1 portion of memory space

Here, both greetings() functions are different, because they have been created at the instantiation. It means we duplicate it every time we create a new User, which takes some memory space.

The more users we create, the more memory it takes, and at some point, it can become a problem. To prevent this, we can use Prototyping, where the function will only be created once, at the prototype level :
function User() {};
User.prototype.greetings = function() {};

const John = new User();
const Jane = new User();
(John.greetings === Jane.greetings); // true
3. Prototype chaining: in JavaScript, each object are descendants or instances of Object.prototype, which is an object that sets properties and methods to all other JavaScript data types. By chaining different objects, we get more properties and methods. But when trying to go further than Object.prototype, you'll get null.

Limits

Despite how powerful prototypal inheritance is, there are still some limits:
  • No loop possible. An error would be raised if we tried the following scenario: if B inherits from A, and C inherits from B, then A cannot inherit from C.
  • Object can only inherit from one prototype. It can be chained, but C cannot inherit directly from both A and B.
  • Prototypal relationships are only between objects (or null)
  • Prototypal chaining can be quite costly: the code search will go up the chain of all prototypes to look for a property until it finds it or reaches null. Depending on how deep the chaining goes, this can be quite expensive for a computer resources.

Sources

More articles

Author(s)

Akira
Akira

Making of : “La nuit des Losers”

lanuitdeslosers.ch, built fast: paper wireframes, a bold hand-drawn identity, then Claude Code to prototype and ship. A mouse-tracking hero animation, a bowling game made of sponsor logos, and a few bugs we’re keeping.
lanuitdeslosers.ch, built fast: paper wireframes, a bold hand-drawn identity, then Claude Code to prototype and ship. A mouse-tracking hero animation, a bowling game made of sponsor logos, and a few bugs we’re keeping.
Making of : “La nuit des Losers”

Author(s)

Pierre
Pierre

Dark mode: necessity or trend

Nous faisons le tri entre idées reçues, réalités techniques et bonnes pratiques de design.
Nous faisons le tri entre idées reçues, réalités techniques et bonnes pratiques de design.
Dark mode: necessity or trend

Author(s)

Yann
Pierre
Yann and Pierre

Experiment #2 – Surway, a social experiments game

Pour notre deuxième expérimentation, nous avons relevé le défi de sortir de notre zone de confort en développant Surway, un jeu vidéo jouable directement dans le navigateur, où les actions de chaque joueur restent inscrites pour tous ceux qui suivront.
Pour notre deuxième expérimentation, nous avons relevé le défi de sortir de notre zone de confort en développant Surway, un jeu vidéo jouable directement dans le navigateur, où les actions de chaque joueur restent inscrites pour tous ceux qui suivront.
Experiment #2 – Surway, a social experiments game