The magic of prototypical inheritance and the prototype chain

If you would like to skip on some technical explanations feel free to skip this section and jump straight to “Tying it all back to React” below.

Let’s examine a simple JavaScript class written in ES6:

class SomeClass {

constructor(config) {

this.instancePropertyOne = config.one;

this.instancePropertyTwo = config.two;

this.instancePropertyThree = config.one + config.two;

} classMethodOne = function classMethodOne() {

console.log(this.instancePropertyOne);

} classMethodTwo = function classMethodTwo() {

console.log(this.instancePropertyTwo);

}

}

And now let’s step back a little and let’s see how we would write it in the ES5 way:

function SomeClass(config) {

this.instancePropertyOne = config.one;

this.instancePropertyTwo = config.two;

this.instancePropertyThree = config.one + config.two;

} SomeClass.prototype.classMethodOne = function classMethodOne() {

console.log(this.instancePropertyOne);

} SomeClass.prototype.classMethodTwo = function classMethodTwo() {

console.log(this.instancePropertyTwo);

}

And to test it:

const config = {one: 1, two: 2}

const someClassInstance = new SomeClass(config); someClassInstance.classMethodOne(); // prints 1

someClassInstance.classMethodOne(); // prints 2

someClassInstance.instancePropertyThree; //prints 3

Now let’s take a closer look.

When we define the class, internally the JavaScript engine does something like this:

function SomeClass(config) {

this.instancePropertyOne = config.one;

this.instancePropertyTwo = config.two;

this.instancePropertyThree = config.one + config.two;

} // The following is an approximation of what happens internally:

// SomeClass.prototype = {constructor: SomeClass}; SomeClass.prototype.classMethodOne = function classMethodOne() {

console.log(this.instancePropertyOne);

} SomeClass.prototype.classMethodTwo = function classMethodTwo() {

console.log(this.instancePropertyTwo);

}

And when we create a new instance of SomeClass with new SomeClass() something like the following happens:

function SomeClass(config) {

// The following is an approximation of what happens internally:

//this = {

__proto__: SomeClass.prototype

};

this.instancePropertyOne = config.one;

this.instancePropertyTwo = config.two;

this.instancePropertyThree = config.one + config.two;

}

As you can see each instance of SomeClass points to the prototype object (or __proto__ ) that is attached to the SomeClass constructor function. The word “points” is of importance here, since almost every variable, property or method in JavaScript is just a pointer to an object instance or primitive value.

This is the prototype chain.

Every object instance, created within the JavaScript environment, points to another prototype object instance called __proto__ , that was provided to it from its constructor function, thus creating a chain.

Start reading from left to right, starting with “var foo = new Foo()”. Source

So, we explained the prototype chain, but what is the prototypical inheritance?

You may have noticed that in our previous class usage example, the SomeClass instance does not actually have any methods on itself. It only has three properties: instancePropertyOne , instancePropertyTwo and instancePropertyThree .

However, when we create a new SomeClass instance and we call someClassInstance.classMethodOne() it works. Why is that so?

That’s because whenever you evaluate a property or a method on an object instance, the JavaScript engine, starting with the object instance itself, will traverse all the __proto__ objects in the the instance’s prototype chain, trying to find a matching property/method key in any of them. If it finds one it will stop searching further and it will use its value.

This is the prototypical inheritance.

As long as any __proto__ object in the prototype chain of an object instance has a property or method with the key/name we are looking for, then it acts as if the object instance itself had the property/method on itself.

If we were trying to use a method that exists in one of the object’s instance __proto__ and we called it as SomeClassInstance.somePrototypeMethod the context for this will be the object instance upon which the method was called (in this case SomeClassInstance ).

So what does this all mean?

The beauty of the prototypical inheritance and the prototype chain, is that even if you have an infinite number of a class’ instances and they all inherit a method from their prototype (class) then all of them will just point to a singular memory address where the prototype method lives.

In essence you are saving memory by allowing all your class instances to use the same function instance by reference.

Foo is a constructor function. b and c are instances of Foo. b and c both share a common prototype and all its methods and properties.

Each time .bind() is called, on the other hand, it creates a new discrete function instance which has to be stored separately in memory.

function SomeClass(config) {

this.instancePropertyOne = config.one;

this.instancePropertyTwo = config.two;

this.instancePropertyThree = config.one + config.two;



// Each instance creates two new functions and references them

this.classMethodOne = this.classMethodOne.bind(this);

this.classMethodTwo = this.classMethodTwo.bind(this); } SomeClass.prototype.classMethodOne = function classMethodOne() {

console.log(this.instancePropertyOne);

} SomeClass.prototype.classMethodTwo = function classMethodTwo() {

console.log(this.instancePropertyTwo);

}

In the code above, if we created 3 SomeClassInstance , 6 new functions would be stored in the memory, when we could use just the 2 initial functions for every SomeClassInstance . Do that thousands of times, instead of 3, and the memory will start filling up gradually.

Tying it all back to React

Applying all the above to React we now realise that .bind ing each and every component method to each component's instance is not a very efficient way to do things if we want to minimize our memory footprint.

(tl;dr if you skipped the two sections above: Every time you call .bind() on a component method you store an extra function in memory, while you could be using the reference to the original method and take advantage of the prototypical inheritance)

That’s especially true when working with big React applications where it’s a common occurrence to have multiple instances of some components.

So what do we do? A good rule of thumb is this:

Does your component have a class method that you need to pass down as a handler to a child component? Then this method needs to be bound to the correct component instance.

That’s because when you pass a method down to a child component as a handler function, you are essentially executing that function from the context of a different object instance, where this is not the one that the method expects.

Example:

class MyComponent extends React.Component {

constructor(props) {

super(props);

this.state={/*...*/};



this.methodOne = this.methodOne.bind(this);

}



methodOne(someValue) {

/* ... */

this.setState({ someState: someValue})

} render() {

return (

/* ... */

<button onClick={this.methodOne}>

Click me!

</button>

) ;

}

}

Every other class method that is only used internally from the component instance does not need to be bound to the component instance.

Example:

class MyComponent extends React.Component {

constructor(props) {

super(props);

this.state={/*...*/}; this.methodOne = this.methodOne.bind(this);

}



methodOne(someValue) {

/* ... */

this.methodTwo();

this.setState({ someState: someValue})

} methodTwo(someOtherValue) {

/* ... */

this.methodThree()

} methodThree() {

// Do something with "this"

} render() {

return (

/* ... */

<button onClick={this.methodOne}>

Click me!

</button>

) ;

}

}

As you can see only methodOne needs to be bound to the component instance since it has to be passed down to a child component as an onClick handler. methodTwo and methodThree do not need to be bound. This way, every MyComponent instance you create will only add one extra function to the memory and for the rest it can use the same MyComponent.prototype methods.

So, next time you try to optimise your React components, keep in mind that unnecessary usage of .bind() can matter.

Thanks for reading! 🖖

Further reading